Hướng dẫn lập trình ADC sử dụng vi điều khiển STM32F103C8T6

Hướng dẫn lập trình ADC sử dụng vi điều khiển STM32F103C8T6
Hướng dẫn lập trình ADC sử dụng vi điều khiển STM32F103C8T6

A, Giới thiệu

Trong bài này mình sẽ hướng dẫn các bạn lập trình với ngoại vi ADC để đọc các tín hiệu analog, Trước tiên chúng ta đi tìm hiểu tín hiệu tương tự, tín hiệu số là gì ?

Tín hiệu tương tự(analog): Tín hiệu Analog là loại tín hiệu liên tục, đồ thị biểu diễn tín hiệu analog là một đường liên tục(ví dụ sin, cos hoặc đường cong lên xuống bất kỳ). Analog có nghĩa là tương tự, tức là tín hiệu sẽ tương tự về bản chất, nhưng sẽ khác nhau về cường độ tín hiệu lúc sau so với lúc trước.

Tín hiệu số(digital): Tín hiệu số là loại tín hiệu rời rạc không nối tiếp nhau theo từng thời điểm. Đây là tín hiệu được thể hiện bằng những con số cụ thể trong computer gọi là nhị phân điện thế 0-1; thể hiện ở 2 ức cao và thấp trong đo mức điên thế cao là 1 và ức điện thấp là 0.

Cả hai tín hiệu số và tương tự đều là tín hiệu phổ biến nhất hiện nay, vậy thì tại sao chúng ta lại cần bộ chuyển ADC để chuyển đổi tương tự sang tín hiệu số ?

  • Tín hiệu số có nhiều ưu điểm hơn so với tín hiệu tương tự : ít nhiễu hơn, dễ truyền đi xa…
  • Tín hiệu số lưu trữ tốt hơn so với tín hiệu analog : Tín hiệu tương tự suy giảm theo thời gian, rất khó có thể lặp lại các sóng analog tại tất cả các thời điểm.

Hiện nay, có rất nhiều cảm biến tín hiệu ouput là tín hiệu tương tự(analog) ví dụ: cảm biến nhiệt độ LM35, độ mặn, đo ion trong nước,….vì vậy ADC là thành phần không thể thiếu trong ứng dụng vi điều khiển.

1, Khối ADC trong STM32F103C8T6

STM32 có tổng cộng 18 kênh ADC nhưng 2 kênh nằm trong chip dành cho cảm biến nhiệt nội và vôn kế nội. như vậy có thể dùng 16 kênh được đánh số lần lượt từ: AIN0,AIN1,…AIN15 để đo tín hiệu analog bên ngoài. Với nhiều mode hoạt động như: single, continuous, scan hoặc discontinuous. Kết quả chuyển đổi được lưu trữ trong thanh ghi 16 bit left-aligned or right-aligned. PCLK2 Bus cung cấp tần số cho bộ ADC và tần số không được vượt quá 14Mhz.

Tính năng chính:

– Độ phân giải 12bit và có thể cấu hình thành 10bit 8bit hoặc 6bit.

– Các ngăt được tạo khi kết thúc chuyển đổi, kết thúc chuyển đổi Injected và các sự kiện Analog watchdog.

– Single, Continuous or Discontinuous mode

– Scan mode: Quét và chuyển đổi từ kênh 0-n –> đa kênh

– Tự hiệu chuẩn.

– Điều khiển chuyển đổi từ bên ngoài sử dụng tín hiệu triger.

– Dual mode: Cả 2 bộ ADC cùng convert các kênh một lúc. Ví dụ ADC1 từ 0-15 và ADC2 từ 15-0.

– Thời gian chuyển đổi nhanh : 1us tại tần số 56Mhz(khoảng 1us một mẫu).

– Vref: điện áp tham chiếu. Đối với chip 144 chân sẽ có chân input điện áp tham chiếu   3.6V >= Vref >= 2.4V và phải có lọc cẩn thận để ADC hoạt động ổn định. Với chip 64 chân trở xuống bạn không cần quan tâm vì điện áp so sánh lấy ở trong chip. Bộ ADC được cấp nguồn riêng từ 2.4V đến 3.6V.

– Điện áp input cho kênh ADC  Vref- <= Vin <= Vref+ : bộ ADC được cấp nguồn trực tiếp 3.3V ==> điện áp tham chiếu Vref+ bằng 3.3V.

– Bộ DMA để tăng tốc độ chuyển đổi

Công thức chuyển đổi : Vin = (Vref * ADCdata)/(Re – 1)  trong đó

Re: Độ phân giải 12bit = 4096, 10bit = 1024, 8bit = 256

2, Sơ đồ khối của bộ ADC trong STM32F103:

Hướng dẫn lập trình ADC sử dụng vi điều khiển STM32F103C8T6

Hoạt động của bộ ADC

  • Hoạt động ở 2 mode :

Independent mode :  hoạt động như ADC thông thường và mỗi một ADCx hoạt động riêng, không phụ thuộc lẫn nhau.

Dual mode : Trong chế độ này thì 2 bộ ADC chuyển đổi đồng thời hoặc có độ trễ không đáng kể và 2 bộ ADC làm việc cùng với nhau như thể chúng chỉ là một bộ ADC.

  • Cơ chế Chuyển đổi A/D

Single Conversion : Một chuyển đổi tại một thời điểm nhất định

Continuous Conversion : Quá trình lấy mẫu và chuyển đổi A/C diễn ra liện tục

Discontinuous Conversion : Chuyển đổi tuần tự một số kênh trong một nhóm.

+ Scan Conversion : lấy mẫu tuần tự và chuyển đổi một loạt các kênh lần lượt

  • 2 nguồn trigger

+ Internal trigger : chuyển đổi A/C được bắt đầu từ code của chương trình

+ External trigger : chuyển đổi A/C được bắt đầu theo các sự kiện phần cứng như ngắt ngoài hoặc ngăt timer.

  • 2 Group : chuyển đổi A/D được thực hiện trong các nhóm và các thành viên trong nhóm là các channels và nó có thể có từ 1 nhóm. Bên trong Group chúng được lên lịch chuyển đổi theo vòng tròn. Chúng ta có thể lập trình trình trình tự chuyển đổi cũng như thời gian lấy mẫu riêng của từng channels. Các nhóm ADC được chia làm 2 loại.

Regular Group : Các channels trong một nhóm là cố định và được chuyển đổi thường xuyên. Tối da là có 16 channels có mặt trong group(n <=8). Tạm hiểu đơn giản một regular group là một đoạn code chạy trong vòng lặp.

Hướng dẫn lập trình ADC sử dụng vi điều khiển STM32F103C8T6

Injected Group : Group này giống như một ngắt có độ ưu tiên cao hơn Regular group, Có tối đa 4 channels trong 1 nhóm. Khi Injected group kích hoạt trên nhóm Regular group thì tất cả các chuyển đổi trên regular group bị tạm thời dừng.  Injected group xử lý xong sau đó  regular group tiếp tục xử lý. Nếu Injected group hoạt động một mình thì nó giống như là Regular group.

Hướng dẫn lập trình ADC sử dụng vi điều khiển STM32F103C8T6

3, Một số thanh ghi quan trọng

1, ADC_DR – ADC regular data register.

Hướng dẫn lập trình ADC sử dụng vi điều khiển STM32F103C8T6

Thanh ghi này chứa giá trị ADC đọc về của các channel regular.

2, ADC_SR – ADC status register.

Hướng dẫn lập trình ADC sử dụng vi điều khiển STM32F103C8T6

Thanh ghi này chứa các cờ báo trạng thái như:
STRT: báo regular channel đã bắt đầu chuyển đổi giá trị ADC hay chưa.
JSTRT: báo injected channel đã bắt đầu chuyển đổi giá trị ADC hay chưa.
JEOC: báo kết thúc quá trình chuyển đổi của  injected channel.
AWD: báo có sự kiện Analog Watchdog có xảy ra hay không.

3, ADC_CR2 – ADC Control register 2.

Hướng dẫn lập trình ADC sử dụng vi điều khiển STM32F103C8T6
Thanh ghi này điều khiển các quá trình chuyển đổi ADC như:
    • TSVREFE: bật hay tắt cảm biến nhiệt độ và Vrefint.
    • SWSTART : bật hay reset trạng thái bộ chuyển đổi liên tục.
    • JSWSTART: bật hay reset trạng thái bộ chuyển đổi liên tục của các injected channels
    • EXTTRIG: cho phép hay không cho phép bắt đầu bộ chuyển đổi liên tục từ xung trigger bên ngoài.
    • EXTSEL[2:0] : bit chọn lựa xung trigger bên ngoài từ nguồn nào.
    • ALIGN : sắp xếp thanh ghi data theo chiều từ lớn đến bé hoặc ngược lại.
    • DMA: có sử dụng bộ DMA hay không.
    • RSTCAL: reset lại thanh ghi calib hay không.
    • CAL: cho phép hay báo là đã calib xong.
    • CONT: lựa chọn mode chuyển đổi liên tục hay chuyển đổi đơn.
    • ADON: bật hay tắt bộ chuyển đổi ADC.

4, ADC_SMPRx – ADC sample time register.

Hướng dẫn lập trình ADC sử dụng vi điều khiển STM32F103C8T6

Hướng dẫn lập trình ADC sử dụng vi điều khiển STM32F103C8T6

Thanh ghi này thiết lập thời gian lấy mẫu nhanh hay chậm và được cài đặt bởi lập trình.SMPx[2:0] tương ứng giá trị nhị phân từ 0->7 sẽ tương ứng với thời gian lấy mầu là: 1.5 – 7.5 – 13.5 – 28.5 – 41.5 – 55.5 – 71.5 – 239.5 cycles. Cách tính thời gian dựa theo hình sau:

B, DEV CODE

1, Lựa chọn Channel ADC

Lập trình GPIO nhấp nháy Led PC13 – STM32F103C8T6

Ở trên kit gồm có 10 channel ADC, chúng  ta sẽ sử dụng channel 1 để đọc điện áp từ một biến trở đưa vào

2, CODE

Mình sử dụng ADC để đo điện áp đặt tại PA1 — ADC1_IN1 qua biến trở 10k, ADC hoạt động ở chế độ Continous mode trên channel1 của ADC1,  Vref = 3.3V

Cấu hình GPIO

void GPIO_Configuration()
{
     GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
     /*PA1 -- ADC1_IN1*/
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
     GPIO_Init(GPIOA,&GPIO_InitStructure);
}

Cấu hình ADC

void ADC_Configuration(void)
{
     ADC_InitTypeDef ADC_InitStructure;
     /*Cấu hình chế độ hoạt động của ADC1*/
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
     ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
     ADC_InitStructure.ADC_ScanConvMode = DISABLE;
     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
     ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
     ADC_InitStructure.ADC_NbrOfChannel = 1;
     ADC_Init(ADC1, &ADC_InitStructure);

     /* ADC1 Channel,  Regular Channel, thời gian lấy mẫu là 55 chu kỳ*/
     ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);
     /*Kích hoạt bộ ADC1 */
     ADC_Cmd(ADC1, ENABLE);
     /* Kích hoạt Reset Calibration, khởi động lại bộ lấy mẫu chuẩn và chờ cho quá trình tái khởi động hoàn tất*/
     ADC_ResetCalibration(ADC1);
     while(ADC_GetResetCalibrationStatus(ADC1));
     /* Kích hoạt chế độ lấy mẫu và cũng chờ cho nó hoàn tất*/
     ADC_StartCalibration(ADC1);
     while(ADC_GetCalibrationStatus(ADC1));
     /* Kích hoạt chế độ chuyển đổi*/
     ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}

Hàm đọc Dữ liệu Analog

uint16_t valueADC = 0;
valueADC = ADC_GetConversionValue(ADC1);

Link tải source tại đây

Chúc bạn thành công!