Giáo trình Thực hành Lập trình hệ thống nhúng STM32F407 - Bài 4: LCD I2C với STM32F407 Discovery

4.1. Chương trình STM32F407 Viết chương trình đọc dữ liệu ADC chân PA4, PA5, PA6 hiển thị dữ liệu lên LCD kiểu giao tiếp I2C dùng STM32F407 4.1.1. Khởi tạo và khai báo dùng STM32CubeMX Trong mục System core chọn RCC, chế độ High speed clock (HSE) chọn Crystal/Ceramic Resonator.

pdf28 trang | Chia sẻ: thanhle95 | Lượt xem: 737 | Lượt tải: 1download
Bạn đang xem trước 20 trang tài liệu Giáo trình Thực hành Lập trình hệ thống nhúng STM32F407 - Bài 4: LCD I2C với STM32F407 Discovery, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 86 Bài 4. LCD I2C VỚI STM32F407 DISCOVERY 4.1. Chương trình STM32F407 Viết chương trình đọc dữ liệu ADC chân PA4, PA5, PA6 hiển thị dữ liệu lên LCD kiểu giao tiếp I2C dùng STM32F407 4.1.1. Khởi tạo và khai báo dùng STM32CubeMX Trong mục System core chọn RCC, chế độ High speed clock (HSE) chọn Crystal/Ceramic Resonator. Trong thẻ connectivity, chọn I2C1: TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 87 Trong thẻ DMA Add thêm I2C1_TX như hình bên dưới TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 88 Tronh thẻ PinOut view Kích chuột vào chân PD12, PD13, PD14, PD15 chọn GPIO_Output Trong thẻ System view chọn GPIO, chọn chân PD12, PD13, PD14, PD15: GPIO output level: LOW GPIO mode: Output Push Pull GPIO Pull-up/Pull-down: No pull-up and no pull-down Maximum output speed: High Tronh thẻ PinOut view Kích chuột vào chân PA4, PA5, PA6 chọn là ADC1_IN4, ADC1_IN5, ADC1_IN6. TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 89 Tronh thẻ PinOut view chọn ADC1. Thẻ DMA settings chọn Add, sau đó chọn ADC1 TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 90 DMA request settings: mode chọn circular Trong ADC1 , thẻ parameter Setting: ADCs_common_settings: Mode: chọn Independent mode TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 91 ADC_settings: Clock prescaler: PCLK2 divided by 2 Resolution : 12 bits (15ADC clock cycles) _ độ phân giải của ADC là 12 bit. Data Alignment: Right Alignment Scan conversion mode: Enalble Continuous conversion mode: Enable Discontinuous conversion mode: Disable DMA continous requests: Enable ADC_regular_Conversionmode: Number of conversion: chọn 3 Rank 1: chọn channel 4 Rank 2: chọn channel 5 Rank 3: chọn channel 6 Trong thẻ Clock Configuration chọn như hình sau: TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 92 Thẻ Project manager: Project name: nhập tên project Project location: chọn nơi lưu project Toolchain/IDE: chọn MDK-ARM TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 93 Chọn open project: TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 94 4.1.2. Chương trình mẫu: Các lệnh sử dụng trong chương trình: Khai báo biến toàn cục: volatile uint16_t adc_value[3]; uint16_t giatri_cb1, giatri_cb2,giatri_cb3; Lệnh cho phép bắt đầu chuyển đổi ADC: HAL_ADC_Start_DMA(&hadc1,(uint32_t*) adc_value,2);cho phép bắt đầu chuyển đổi adc1 có DMA. Sau khi STM chuyển đổi xong sẽ thực hiện chương trình ngắt sau: TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 95 Chương trình mẫu toàn code: #include "main.h" ADC_HandleTypeDef hadc1; DMA_HandleTypeDef hdma_adc1; I2C_HandleTypeDef hi2c1; DMA_HandleTypeDef hdma_i2c1_tx; /* USER CODE BEGIN PV */ volatile uint16_t adc_value[3]; uint16_t giatri_cb1, giatri_cb2,giatri_cb3; /* USER CODE END PV */ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_DMA_Init(void); static void MX_I2C1_Init(void); static void MX_ADC1_Init(void); /* USER CODE BEGIN PFP */ void lcd_send_cmd4bit (int8_t cmd); void lcd_send_cmd (char cmd); void lcd_init (void); void lcd_send_data(char chr); /* USER CODE END PFP */ int main(void) TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 96 { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); MX_I2C1_Init(); MX_ADC1_Init(); /* USER CODE BEGIN 2 */ HAL_ADC_Start_DMA(&hadc1,(uint32_t*) adc_value,2); lcd_init(); lcd_send_cmd(0x80); HAL_Delay(100); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 97 while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ lcd_send_cmd(0x80); lcd_send_data('A'); HAL_Delay(300); giatri_cb1= adc_value[0]; giatri_cb2= adc_value[1]; lcd_send_cmd(0xC0); lcd_send_data(giatri_cb1/1000%10+0x30); lcd_send_data(giatri_cb1/100%10+0x30); lcd_send_data(giatri_cb1/10%10+0x30); lcd_send_data(giatri_cb1/1%10+0x30); lcd_send_cmd(0xC8); lcd_send_data(giatri_cb2/1000%10+0x30); lcd_send_data(giatri_cb2/100%10+0x30); lcd_send_data(giatri_cb2/10%10+0x30); lcd_send_data(giatri_cb2/1%10+0x30); } /* USER CODE END 3 */ } TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 98 /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SC ALE1); /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = 8; RCC_OscInitStruct.PLL.PLLN = 336; TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 99 RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 4; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) { Error_Handler(); } } /** TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 100 * @brief ADC1 Initialization Function * @param None * @retval None */ static void MX_ADC1_Init(void) { /* USER CODE BEGIN ADC1_Init 0 */ /* USER CODE END ADC1_Init 0 */ ADC_ChannelConfTypeDef sConfig = {0}; /* USER CODE BEGIN ADC1_Init 1 */ /* USER CODE END ADC1_Init 1 */ /** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) */ hadc1.Instance = ADC1; hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; hadc1.Init.Resolution = ADC_RESOLUTION_12B; hadc1.Init.ScanConvMode = ENABLE; hadc1.Init.ContinuousConvMode = ENABLE; hadc1.Init.DiscontinuousConvMode = DISABLE; TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 101 hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 2; hadc1.Init.DMAContinuousRequests = ENABLE; hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; if (HAL_ADC_Init(&hadc1) != HAL_OK) { Error_Handler(); } /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. */ sConfig.Channel = ADC_CHANNEL_4; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_84CYCLES; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } /** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. */ sConfig.Channel = ADC_CHANNEL_5; sConfig.Rank = 2; TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 102 if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN ADC1_Init 2 */ /* USER CODE END ADC1_Init 2 */ } /** * @brief I2C1 Initialization Function * @param None * @retval None */ static void MX_I2C1_Init(void) { /* USER CODE BEGIN I2C1_Init 0 */ /* USER CODE END I2C1_Init 0 */ /* USER CODE BEGIN I2C1_Init 1 */ /* USER CODE END I2C1_Init 1 */ TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 103 hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 400000; hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN I2C1_Init 2 */ /* USER CODE END I2C1_Init 2 */ } /** * Enable DMA controller clock */ static void MX_DMA_Init(void) { TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 104 /* DMA controller clock enable */ __HAL_RCC_DMA1_CLK_ENABLE(); __HAL_RCC_DMA2_CLK_ENABLE(); /* DMA interrupt init */ /* DMA1_Stream6_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn); /* DMA2_Stream0_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn); } /** * @brief GPIO Initialization Function * @param None * @retval None */ static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOH_CLK_ENABLE(); TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 105 __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_RESET); /*Configure GPIO pins : PD12 PD13 PD14 PD15 */ GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); } /* USER CODE BEGIN 4 */ void lcd_init (void) { // 4 bit initialisation HAL_Delay(100); // wait for >40ms lcd_send_cmd4bit(0x00); lcd_send_cmd4bit (0x30); TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 106 HAL_Delay(50); // wait for >4.1ms lcd_send_cmd4bit (0x30); HAL_Delay(5); // wait for >100us lcd_send_cmd4bit (0x30); HAL_Delay(1); lcd_send_cmd4bit (0x20); // 4bit mode HAL_Delay(1); // dislay initialisation lcd_send_cmd (0x28); // Function set --> DL=0 (4 bit mode), N = 1 (2 line display) F = 0 (5x8 characters) HAL_Delay(1); lcd_send_cmd (0x08); //Display on/off control --> D=0,C=0, B=0 ---> display off HAL_Delay(1); lcd_send_cmd (0x01); // clear display HAL_Delay(1); HAL_Delay(1); lcd_send_cmd (0x06); //Entry mode set --> I/D = 1 (increment cursor) & S = 0 (no shift) HAL_Delay(1); lcd_send_cmd (0x0C); //Display on/off control --> D = 1, C and B = 0. (Cursor and blink, last two bits) HAL_Delay(1); } void lcd_send_cmd (char cmd) TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 107 { char data_u, data_l; uint8_t data_t[4]; data_u = cmd&0xf0; // select only upper nibble data_l = (cmd<<4)&0xf0; // select only lower nibble data_t[0] = data_u|0x04; //en=1, rs=0 data_t[1] = data_u; //en=0, rs=0 data_t[2] = data_l|0x04; //en=1, rs=0 data_t[3] = data_l; //en=0, rs=0 HAL_I2C_Master_Transmit (&hi2c1, 0x4E, (uint8_t *) data_t, 4, 200); } void lcd_send_data(char chr){ char data_u, data_l; uint8_t data_t[4]; data_u = chr&0xf0; // select only upper nibble data_l = (chr<<4)&0xf0; // select only lower nibble data_t[0] = data_u|0x04|0x01; //en=1, rs=1 data_t[1] = data_u|0x01; //en=0, rs=1 data_t[2] = data_l|0x04|0x01; //en=1, rs=1 data_t[3] = data_l|0x01; //en=0, rs=1 HAL_I2C_Master_Transmit (&hi2c1, 0x4E, (uint8_t *) data_t, 4, 200); } #define LCD_EN 2 TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 108 #define LCD_RW 1 #define LCD_RS 0 #define LCD_D4 4 void lcd_send_cmd4bit (int8_t cmd){ //cmd la 4bit 0xcmd_0 char data_u; uint8_t data_t[4]; data_u = cmd&0xf0; // select only upper nibble data_t[0] = data_u|0x04; //en=1, rs=0 data_t[1] = data_u; //en=0, rs=0 HAL_I2C_Master_Transmit (&hi2c1, 0x4E, (uint8_t *) data_t, 2, 200); } /* USER CODE END 4 */ void Error_Handler(void) { } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 109 * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ 4.1.3. Biên dịch và nạp chương trình: Biên dịch chương trình và download chương trình: TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 110 4.2. Giải thích chương trình 4.2.1. Chương trình lcd_send_cmd4bit Chương trình này để gởi lệnh 4 bit cho LCD. Vì theo datasheet của HD44780 LCD ta có như sau: Có nghĩa là khi mở nguồn chờ 15ms Sau đó gởi lệnh 0X03 sau đó chờ 4.1ms -> gởi lệnh 0x03 -> chờ 100us -> gởi lệnh 0x03 sau đó lệnh 0x02. Tất cả các lệnh này đều thẻ hiện 4 bit. Vì vậy trong hàm khởi tạo LCD (lcd_init) ta phải thực hiện lệnh 4 bit trước. TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 111 Nếu không thực hiện điều này LCD bị sai trong lúc nhấn reset vi điều khiển void lcd_send_cmd4bit (int8_t cmd){ //cmd la 4bit 0xcmd_0 char data_u; uint8_t data_t[4]; data_u = cmd&0xf0; // select only upper nibble data_t[0] = data_u|0x04; //en=1, rs=0 data_t[1] = data_u; //en=0, rs=0 HAL_I2C_Master_Transmit (&hi2c1, 0x4E, (uint8_t *) data_t, 2, 100); } 4.2.2. Chương trình lcd_send_cmd Chương trình này gởi lệnh cho LCD, đầu tiên gởi lệnh 4 bit cao, sau đó là 4 bit thấp void lcd_send_cmd (char cmd) { char data_u, data_l; uint8_t data_t[4]; data_u = cmd&0xf0; // select only upper nibble data_l = (cmd<<4)&0xf0; // select only lower nibble data_t[0] = data_u|0x04; //en=1, rs=0 data_t[1] = data_u; //en=0, rs=0 data_t[2] = data_l|0x04; //en=1, rs=0 data_t[3] = data_l; //en=0, rs=0 HAL_I2C_Master_Transmit (&hi2c1, 0x4E, (uint8_t *) data_t, 4, 100); } TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 112 4.2.3. Chương trình lcd_send_data Chương trình này để hiển thị dữ liệu lên LCD void lcd_send_data(char chr){ char data_u, data_l; uint8_t data_t[4]; data_u = chr&0xf0; // select only upper nibble data_l = (chr<<4)&0xf0; // select only lower nibble data_t[0] = data_u|0x04|0x01; //en=1, rs=1 data_t[1] = data_u|0x01; //en=0, rs=1 data_t[2] = data_l|0x04|0x01; //en=1, rs=1 data_t[3] = data_l|0x01; //en=0, rs=1 HAL_I2C_Master_Transmit (&hi2c1, 0x4E, (uint8_t *) data_t, 4, 100); } 4.2.4. Chương trình lcd_init Chương trình này để khởi tạo LCD theo datasheet của HD44780 LCD trang 46. Đã được giải thích trong mục 4.2.1 void lcd_init (void) { HAL_Delay(100); // wait for >40ms lcd_send_cmd4bit(0x00); lcd_send_cmd4bit (0x30); HAL_Delay(50); // wait for >4.1ms lcd_send_cmd4bit (0x30); HAL_Delay(5); // wait for >100us TH LẬP TRÌNH HỆ THỐNG NHÚNG STM32F407 - TDMU Ngô Thanh Đông 113 lcd_send_cmd4bit (0x30); HAL_Delay(1); lcd_send_cmd4bit (0x20); // 4bit mode HAL_Delay(1); lcd_send_cmd (0x28); // Function set --> DL=0 (4 bit mode), N = 1 (2 line display) F = 0 (5x8 characters) HAL_Delay(1); lcd_send_cmd (0x08); //Display on/off control --> D=0,C=0, B=0 ---> display off HAL_Delay(1); lcd_send_cmd (0x01); // clear display HAL_Delay(1); HAL_Delay(1); lcd_send_cmd (0x06); //Entry mode set --> I/D = 1 (increment cursor) & S = 0 (no shift) HAL_Delay(1); lcd_send_cmd (0x0C); //Display on/off control --> D = 1, C and B = 0. (Cursor and blink, last two bits) HAL_Delay(1); } 4.3. Bài tập thực hành 4.3.1. Câu 1: Vẽ lưu đồ và viết chương trình hiển thị chuỗi Họ và tên lên LCD.