BÀI 4: LẬP TRÌNH CÁC ỨNG DỤNG SỬ DỤNG ADC Trang bị cho sinh viên các kiến thức về bộ chuyển đổi tương tự số ADC trong vi điều khiển ARM STM32. Cách lập trình sử dụng ADC để thiết kế ứng dụng. Sinh viên nắm được: Các nguyên tắc hoạt động, các chế độ hoạt động của ADC Cách lập trình một chương trình có sử ADC.
BÀI LẬP TRÌNH CÁC ỨNG DỤNG SỬ DỤNG ADC Mục đích Trang bị cho sinh viên kiến thức chuyển đổi tương tự số - ADC vi điều khiển ARM STM32 Cách lập trình sử dụng ADC để thiết kế ứng dụng Yêu cầu Sinh viên nắm được: - Các nguyên tắc hoạt động, chế độ hoạt động ADC - Cách lập trình chương trình có sử ADC Giới thiệu ADC ARM STM32 - ADC STM32F103 có độ phân giải 12 Bit - Có 20 kênh ADC có 20 kênh bên ngồi : ADC1_IN0 ÷ ADC1_IN9; ADC2_IN0 ÷ ADC2_IN9 kênh bên chip: Vrefint cảm biến nhiệt độ - Chuyển đổi A/D kênh thực với chế độ: Single; Continuous; Scan; Discontinuous - Giá trị ADC sau chuyển đổi xong lưu trữ ghi 16 bit (lưu trữ theo định dạng left-aligned right-aligned) - Xung nhịp ADC thuộc khối clock APB2 Nguyên tắc hoạt động ADC 2.1 Sơ đồ hoạt động ADC Hình 1.1: Sơ đồ khối ADC Hình 1.2: Thơng số chân chức ADC Hình 1.3: Giản đồ thời gian chuyển đổi ADC - ADC_CLK điều khiển đồng với PCLK2(APB2) - ADC_CLK tạo từ RCC với hệ số chia tần thiết lập chương trình 2.2 Lựa chọn kênh ADC Hình 1.4: Các khối ADC - Hình 1.2 mơ tả hoạt động ADC: 10 kênh ADC tổ chức chuyển đổi theo nhóm: Regular Injected - Một nhóm bao gồm chuỗi chuyển đổi thực kênh theo thứ tự - - Ví dụ: ADC_IN3, ADC_IN8 ADC_IN2, ADC_IN2 ADC_IN0, ADC_IN2 ADC_IN2, ADC_IN9 Chế độ Regular : gồm tối đa 16 kênh Lựa chọn kênh thứ tự chuyển đổi thiết lập ghi ADC_SQRx - Chế độ Injected: gồm tối đa kênh Lựa chọn kênh thứ tự chuyển đổi thiết lập ghi ADC_JSQR - Temperature sensor /VREFIN : Cảm biến nhiệt độ kết nối với kênh ADCx_IN16 điện áp tham chiếu bên trongVREFINT kết nối với ADCx_IN17 Hai kênh thiết lập Regular Injected - Lưu ý: Temperature sensor /VREFIN thực với ADC1 Thời gian lấy mẫu - Thời gian lấy mẫu kênh ADC thiết lập cách sử dụng bit SMP [2: 0] ghi ADC_SMPR1 ADC_SMPR2 Mỗi kênh lấy mẫu với thời gian lấy mẫu khác - Tổng thời gian chuyển đổi tính sau: Tconv = Sampling time + 12.5 cycles Ví dụ: ADCCLK = 14 MHz Sampling time = 1.5 cycles: Tconv = (1.5 + 12.5) cycles = 14 cycles = µs 2.3 Các chế độ hoạt động ADC - ADC STM32 thực với chế độ: Single; Continuous; Scan; Discontinuous Hình 1.5: Các chế độ hoạt động ADC - ADC STM32 có cách lưu trữ liệu sau chuyển đổi xong hình 1.6 Hình 1.6: Các chế độ lưu trữ liệu THIẾT KẾ ỨNG DỤNG SỬ DỤNG ADC 3.1 Các hàm sử dụng API HAL - HAL_ADC_Start: hàm khởi tạo chuyển đổi ADC không ngắt - HAL_ADC_Start_IT: hàm khởi tạo chuyển đổi ADC có ngắt - HAL_ADC_GetValue: hàm trả giá trị ADC chuyển đổi - HAL_ADC_Stop: hàm dừng chuyển đổi ADC không ngắt - HAL_ADC_Stop_IT: hàm dừng chuyển đổi ADC có ngắt - HAL_ADC_Start_DMA: hàm khởi tạo chuyển đổi ADC DMA - HAL_ADC_Stop_DMA: hàm dừng chuyển đổi ADC DMA - HAL_ADC_PollForConversion: hàm chờ ADC chuyển đổi xong 3.2 Các bước lập trình với ADC STM32CubeMX Bước Thiết lập hệ thống - Thiết lập xung nhịp hệ thống : SystemClock_Config() Bước Thiết lập cho GPIO, xung nhịp ADC - Cho phép GPIO – AFIO tương ứng hoạt động hàm: HAL_RCC_GPIOx_CLK_ENABLE(); HAL_RCC_ADCx_CLK_ENABLE(); Bước Cấu hình cho chuyển đổi ADC - Lựa chọn kênh đầu vào ADC: - Cho phép ADC bắt đầu chuyển đổi: HAL_ADC_Start(&hadc1); - Chờ ADC chuyển đổi xong: HAL_ADC_PollForConversion(&hadc1,10); - Đọc giá trị ADC chuyển đổi xong: AD=HAL_ADC_GetValue(&hadc1); Thiết lập STMCubeMx B1 Cấu hình nguồn xung ADC: ADC1, ADC2 – APB2 B2 Cấu hình ADC: Lựa chọn ADC; Lựa chọn kênh ADC; Cấu hình ADC - Cấu hình ADC + ADC_Setting + ADC_Regular Conversions + Rank Lựa chọn chân chiều vào, chiều ra, mode Thiết lập thông số STM32CubeMX hướng dẫn lập trình với GPIO Sau chọn GENERATE CODE để tạo file Code - Khung chương trình với ADC #include "main.h" ADC_HandleTypeDef hadc1; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_ADC1_Init(void); uint32_t AD; int main(void){ HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_ADC1_Init(); while (1){ HAL_ADC_Start(&hadc1); HAL_ADC_PollForConversion(&hadc1,10); AD=HAL_ADC_GetValue(&hadc1); } } static void MX_ADC1_Init(void){ ADC_ChannelConfTypeDef sConfig = {0}; hadc1.Instance = ADC1; hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE; hadc1.Init.ContinuousConvMode = ENABLE; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 1; if (HAL_ADC_Init(&hadc1) != HAL_OK){Error_Handler();} sConfig.Channel = ADC_CHANNEL_0; sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK){ Error_Handler(); }} Ví dụ : Sử dụng đọc tín hiệu ADC ADC – Kênh (ADC1_IN0 - PA0) Hiển thị giá trị ADC mã nhị phân D0 ÷ D11 12 LED - kết nối từ PB4 ÷ PB15 Bộ tạo dao động chế độ HSI với Fosc = 8MHz Chương trình: #include "main.h" ADC_HandleTypeDef hadc1; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_ADC1_Init(void); uint32_t AD; void hienthi_12bit(unsigned int data) { HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4, HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5, HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6, HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7, HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8, HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9, HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10, HAL_GPIO_WritePin(GPIOB,GPIO_PIN_11, HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12, HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13, HAL_GPIO_WritePin(GPIOB,GPIO_PIN_14, HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15, } int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_ADC1_Init(); data&0x01); (data>>1)&0x001); (data>>2)&0x001); (data>>3)&0x001); (data>>4)&0x001); (data>>5)&0x001); (data>>6)&0x001); (data>>7)&0x001); (data>>8)&0x001); (data>>9)&0x001); (data>>10)&0x001); (data>>11)&0x001); while (1) { HAL_ADC_Start(&hadc1); HAL_ADC_PollForConversion(&hadc1,10); AD=HAL_ADC_GetValue(&hadc1); hienthi_12bit(AD); } } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {Error_Handler();} RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK){Error_Handler();} PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC; PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV2; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {Error_Handler();} } static void MX_ADC1_Init(void){ ADC_ChannelConfTypeDef sConfig = {0}; hadc1.Instance = ADC1; hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE; hadc1.Init.ContinuousConvMode = ENABLE; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 1; if (HAL_ADC_Init(&hadc1) != HAL_OK){Error_Handler();} sConfig.Channel = ADC_CHANNEL_0; sConfig.Rank = ADC_REGULAR_RANK_1; sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK){ Error_Handler(); }} static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; HAL_RCC_GPIOA_CLK_ENABLE(); HAL_RCC_GPIOB_CLK_ENABLE(); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13 |GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_4|GPIO_PIN_5 |GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9, GPIO_PIN_RESET); GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13 |GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_4|GPIO_PIN_5 |GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); } Ví dụ : Sử dụng đọc tín hiệu ADC ADC – Kênh (ADC1_IN1 – PA1) Hiển thị giá trị thập phân đầu vào ADC lên Led kết nối với PORT B Bộ tạo dao động chế độ HSI với Fosc = 8MHz 50% RV1 1k U1 10 11 12 13 14 15 16 17 29 30 31 32 33 34 37 38 18 19 20 39 40 41 42 43 45 46 21 22 25 26 27 28 PA0-WKUP PA1 PA2 PA3 PA4 PA5 PA6 PA7 PA8 PA9 PA10 PA11 PA12 PA13 PA14 PA15 PB0 PB1 PB2 PB3 PB4 PB5 PB6 PB7 PB8 PB9 PB10 PB11 PB12 PB13 PB14 PB15 NRST PC13_RTC PC14-OSC32_IN PC15-OSC32_OUT STM32F103C6 Chương trình: OSCIN_PD0 OSCOUT_PD1 VBAT BOOT0 44 #include "main.h" ADC_HandleTypeDef hadc1; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_ADC1_Init(void); unsigned int adc; char ma_led[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; void hienthi_7seg(unsigned char data) { HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8, data&0x01); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9, (data>>1)&0x01); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10, (data>>2)&0x01); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_11, (data>>3)&0x01); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12, (data>>4)&0x01); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13, (data>>5)&0x01); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_14, (data>>6)&0x01); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15, (data>>7)&0x01); } int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_ADC1_Init(); HAL_ADC_Start(&hadc1); while (1) { HAL_ADC_PollForConversion(&hadc1,10); adc=HAL_ADC_GetValue(&hadc1); //Nghin HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3, HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4, HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5, HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6, hienthi_7seg(ma_led[adc/1000]); HAL_Delay(2); //Tram HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3, HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4, HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5, HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6, hienthi_7seg(ma_led[adc%1000/100]); HAL_Delay(2); GPIO_PIN_SET); GPIO_PIN_RESET); GPIO_PIN_RESET); GPIO_PIN_RESET); GPIO_PIN_RESET); GPIO_PIN_SET); GPIO_PIN_RESET); GPIO_PIN_RESET); //Chuc HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6, GPIO_PIN_RESET); hienthi_7seg(ma_led[adc%1000%100/10]); HAL_Delay(2); //Don vi HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6, GPIO_PIN_SET); hienthi_7seg(ma_led[adc%1000%100%10]); HAL_Delay(2); } } - Phần khởi tạo thiết lập vào liệu giống ví dụ BÀI TẬP Bài tập Sử dụng đọc tín hiệu ADC ADC – Kênh (ADC1_IN1 – PA1) Hiển thị giá trị ADC mã nhị phân D0 ÷ D11 12 LED - kết nối từ PB0 ÷ PB11 Bộ tạo dao động chế độ HSI với Fosc = 8MHz Bài tập Sử dụng đọc tín hiệu ADC ADC – Kênh (ADC2_IN2 – PA2) Hiển thị giá trị ADC mã nhị phân D0 ÷ D11 12 LED - kết nối từ PB0 ÷ PB11 Bộ tạo dao động chế độ HSI với Fosc = 8MHz Bài tập Sử dụng đọc tín hiệu ADC ADC – Kênh (ADC1_IN4 – PA4) Hiển thị giá trị Volt đầu vào ADC lên Led kết nối với PORT B Bộ tạo dao động chế độ HSI với Fosc = 8MHz Bài tập Sử dụng đọc tín hiệu ADC ADC – Kênh (ADC1_IN1 – PA1) Hiển thị giá trị Volt đầu vào ADC lên LCD 16x2 kết nối với PORT B Bộ tạo dao động chế độ HSI với Fosc = 8MHz Bài tập Sử dụng đọc tín hiệu cảm biến nhiệt độ LM35 ADC – Kênh (ADC1_IN1 – PA1) Hiển thị nhiệt độ đo lên LED LCD 16x2 kết nối với PORT B Bộ tạo dao động chế độ HSI với Fosc = 8MHz ... dụ BÀI TẬP Bài tập Sử dụng đọc tín hiệu ADC ADC – Kênh (ADC1_IN1 – PA1) Hiển thị giá trị ADC mã nhị phân D0 ÷ D11 12 LED - kết nối từ PB0 ÷ PB11 Bộ tạo dao động chế độ HSI với Fosc = 8MHz Bài. .. Conversions + Rank Lựa chọn chân chiều vào, chiều ra, mode Thiết lập thơng số STM32CubeMX hướng dẫn lập trình với GPIO Sau chọn GENERATE CODE để tạo file Code - Khung chương trình với ADC... với Fosc = 8MHz Bài tập Sử dụng đọc tín hiệu ADC ADC – Kênh (ADC1_IN4 – PA4) Hiển thị giá trị Volt đầu vào ADC lên Led kết nối với PORT B Bộ tạo dao động chế độ HSI với Fosc = 8MHz Bài tập Sử dụng