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.
Trang 1BÀI 4 LẬP TRÌNH CÁC ỨNG DỤNG SỬ DỤNG ADC
Mục đích
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
Yêu cầu
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
1 Giới thiệu ADC trong ARM STM32
- ADC của STM32F103 có độ phân giải 12 Bit
- Có 20 kênh ADC trong đó có 20 kênh bên ngoài : ADC1_IN0 ÷ ADC1_IN9; ADC2_IN0
÷ ADC2_IN9 và 2 kênh bên trong chip: Vrefint và cảm biến nhiệt độ
- Chuyển đổi A/D trên các kênh có thể thực hiện với 4 chế độ: Single; Continuous; Scan; Discontinuous
- Giá trị ADC sau khi chuyển đổi xong được lưu trữ trong thanh ghi 16 bit (lưu trữ theo 2 định dạng left-aligned hoặc right-aligned)
- Xung nhịp ADC thuộc khối clock APB2
2 Nguyên tắc hoạt động của ADC
2.1 Sơ đồ hoạt động của ADC
Hình 1.1: Sơ đồ khối của ADC
Trang 2Hình 1.2: Thông số các chân chức năng của ADC
Hình 1.3: Giản đồ thời gian chuyển đổi ADC
- ADC_CLK được điều khiển và đồng bộ với PCLK2(APB2)
- ADC_CLK được tạo ra từ RCC với hệ số chia tần thiết lập bằng chương trình
Trang 3
2.2 Lựa chọn kênh ADC
Hình 1.4: Các khối cơ bản của ADC
- Hình 1.2 mô tả hoạt động của ADC: 10 kênh của 1 bộ ADC có thể tổ chức chuyển
đổi theo 2 nhóm: Regular và Injected
- Một nhóm bao gồm một chuỗi chuyển đổi có thể được thực hiện trên bất kỳ kênh nào
và theo thứ tự bất kỳ
- 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 và thứ tự chuyển đổi được
thiết lập trong thanh ghi ADC_SQRx
- Chế độ Injected: gồm tối đa 4 kênh Lựa chọn kênh và thứ tự chuyển đổi được thiết
lập trong thanh ghi ADC_JSQR
- Temperature sensor /VREFIN : Cảm biến nhiệt độ được kết nối với kênh
ADCx_IN16 và điện áp tham chiếu bên trongVREFINT được kết nối với
ADCx_IN17 Hai kênh có thể được thiết lập trong Regular hoặc Injected
- Lưu ý: Temperature sensor /VREFIN chỉ thực hiện với ADC1
Thời gian lấy mẫu
Trang 4- Thời gian lấy mẫu của các kênh ADC có thể được thiết lập bằng cách sử dụng các bit SMP [2: 0] trong thanh ghi ADC_SMPR1 và ADC_SMPR2 Mỗi kênh có thể được lấy mẫu với thời gian lấy mẫu khác
- Tổng thời gian chuyển đổi được tính như sau:
Tconv = Sampling time + 12.5 cycles
Ví dụ:
ADCCLK = 14 MHz và Sampling time = 1.5 cycles:
Tconv = (1.5 + 12.5) cycles = 14 cycles = 1 µs
2.3 Các chế độ hoạt động của ADC
- ADC trên STM32 có thể thực hiện với 4 chế độ: Single; Continuous; Scan;
Discontinuous.
Hình 1.5: Các chế độ hoạt động của ADC
- ADC trên STM32 có 4 cách lưu trữ dữ liệu sau khi chuyển đổi xong như hình 1.6
Trang 5Hình 1.6: Các chế độ lưu trữ dữ liệu
3 THIẾT KẾ ỨNG DỤNG SỬ DỤNG ADC
3.1 Các hàm sử dụng trong 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ả về 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 trên STM32CubeMX
Trang 6Bước 1 Thiết lập hệ thống
- Thiết lập xung nhịp hệ thống : SystemClock_Config()
Bước 2 Thiết lập cho các GPIO, xung nhịp ADC
- Cho phép GPIO – AFIO tương ứng hoạt động bằng hàm:
HAL_RCC_GPIOx_CLK_ENABLE(); HAL_RCC_ADCx_CLK_ENABLE();
Bước 3 Cấu hình cho bộ chuyển đổi ADC
- Lựa chọn kênh đầu vào ADC:
- Cho phép ADC và 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 trên STMCubeMx
B1 Cấu hình nguồn xung của ADC: ADC1, ADC2 – APB2
Trang 7B2 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
Trang 8 Lựa chọn chân chiều vào, chiều ra, mode Thiết lập các thông số trên STM32CubeMX như trong 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ụ 1 : Sử dụng đọc tín hiệu ADC trên ADC 1 – Kênh 0 (ADC1_IN0 - PA0)
Hiển thị giá trị ADC bằng mã nhị phân D0 ÷ D11 lần lượt trên 12 LED - kết nối từ PB4 ÷ PB15 Bộ tạo dao động chế độ HSI với Fosc = 8MHz
Trang 9Chươ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, data&0x01);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5, (data>>1)&0x001); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6, (data>>2)&0x001); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_7, (data>>3)&0x001); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8, (data>>4)&0x001); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9, (data>>5)&0x001); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_10, (data>>6)&0x001); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_11, (data>>7)&0x001); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12, (data>>8)&0x001); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13, (data>>9)&0x001); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_14, (data>>10)&0x001); HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15, (data>>11)&0x001); }
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_ADC1_Init();
Trang 10while (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();
Trang 11}}
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ụ 2 : Sử dụng đọc tín hiệu ADC trên ADC 1 – Kênh 1 (ADC1_IN1 – PA1) Hiển thị
giá trị thập phân của đầu vào ADC lên 4 Led 7 thanh kết nối với PORT B Bộ tạo dao động
chế độ HSI với Fosc = 8MHz
Chương trình:
BOOT0 44
NRST 7 PA0-WKUP
10
OSCIN_PD0 5 OSCOUT_PD1 6
PB8 45
PA2
12 PA1 11
PA3 13 PA4 14
PB9 46
PA5 15 PA6 16 PA7 17 PA8 29 PA9 30
PB10 21
PA10 31
PB0 18 PB1 19 PB2 20 PB3 39
PB11 22
PB4 40 PB5 41 PB6 42 PB7 43
PB12 25 PB13 26 PB14 27 PB15 28
PA11 32 PA12 33 PA13 34 PA14 37 PA15
PC14-OSC32_IN 3 PC15-OSC32_OUT 4
VBAT 1
U1
STM32F103C6
RV1
1k
Trang 12#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, GPIO_PIN_SET);
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_RESET);
hienthi_7seg(ma_led[adc/1000]);
HAL_Delay(2);
//Tram
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6, GPIO_PIN_RESET);
hienthi_7seg(ma_led[adc%1000/100]);
HAL_Delay(2);
//Chuc
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4, GPIO_PIN_RESET);
Trang 13HAL_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 và thiết lập vào ra dữ liệu giống như ví dụ 1
4 BÀI TẬP
Bài tập 1
Sử dụng đọc tín hiệu ADC trên ADC 1 – Kênh 1 (ADC1_IN1 – PA1) Hiển thị giá trị ADC bằng mã nhị phân D0 ÷ D11 lần lượt trên 12 LED - kết nối từ PB0 ÷ PB11 Bộ tạo dao động chế độ HSI với Fosc = 8MHz
Bài tập 2
Sử dụng đọc tín hiệu ADC trên ADC 2 – Kênh 2 (ADC2_IN2 – PA2) Hiển thị giá trị ADC bằng mã nhị phân D0 ÷ D11 lần lượt trên 12 LED - kết nối từ PB0 ÷ PB11 Bộ tạo dao động chế độ HSI với Fosc = 8MHz
Bài tập 3
Sử dụng đọc tín hiệu ADC trên ADC 1 – Kênh 4 (ADC1_IN4 – PA4) Hiển thị giá trị Volt
của đầu vào ADC lên 4 Led 7 thanh kết nối với PORT B Bộ tạo dao động chế độ HSI với Fosc = 8MHz
Bài tập 4
Sử dụng đọc tín hiệu ADC trên ADC 1 – Kênh 1 (ADC1_IN1 – PA1) Hiển thị giá trị Volt
của đầ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 5
Sử dụng đọc tín hiệu của cảm biến nhiệt độ LM35 trên ADC 1 – Kênh 1 (ADC1_IN1 – PA1)
Hiển thị nhiệt độ đo được lên 4 LED 7 thanh hoặc LCD 16x2 kết nối với PORT B Bộ tạo dao động chế độ HSI với Fosc = 8MHz