Bài 8: Lập trình STM32 đọc ADC một kênh

ADC một kênh

Lập trình STM32 đọc ADC một kênh sẽ giúp các bạn

  • Hiểu ADC là gì
  • Cách cấu hình ADC trên STM32 Cube MX
  • Cách lập trình ADC chế độ Single Mode và Continuous Mode

Bài 8 trong serie Học lập trình STM32 từ A tới Z

ADC là gì?

ADC Analog to Digital Convert là bộ chuyển đôi tương tự sang số. Đại lượng tương tự là Điện áp Vin được so sánh với điện áp mẫu Vref (giá trị lớn nhất), sau đó được chuyển đổi thành số lưu vào thanh ghi DATA của bộ chuyển đổi đó.

Có 2 tham số quan trọng của bộ ADC cần lưu ý:

  • Tốc độ lấy mẫu (sampling) được tính theo số chu kì chuyển đổi
  • Độ phân giải: Tính theo Bit bộ ADC có độ phân giải 10 Bit sẽ có 2^10 = 1024 giá trị
H1

Các chức năng chính của ADC trong STM32 

Độ phân giải 12Bit

Sinh ra ngắt tại các sự kiện End of convert, End of Injected, Analog Watchdog

Chế độ Single hoặc Continuous

Chế độ Scan tự động quét từ Kênh 0 đến Kênh n (mỗi bộ có 10 kênh tối đa)

Có cơ chế cân chỉnh tay

Data Alignment (Căn chỉnh Data) căn trái hoặc căn phải

Cài đặt thời gian chuyển đổi đến từng Kênh

Có thể kích hoạt bằng xung bên ngoài

Chế độ Dual mode sử dụng cùng lúc 2 hoặc nhiều bộ ADC

Hỗ trợ DMA

Tần số chuyển đổi ADC được lấy từ bộ ABP2 thông qua ADC prescaler và phải nhỏ hơn 14mhz

H2 6

Chi tiết tham khảo mục 11.2 trong reference manual

ACD một kênh chế độ Single và Continuous

Với chế độ Single bộ ADC chỉ chuyển đổi 1 lần rồi dừng, một sự kiện ngắt được sinh ra nếu bit EOCIR được set lên 1

Với chế độ Continuous bộ ADC sẽ chuyển đổi liên tục, một sự kiện ngắt được sinh ra nếu bit EOCIR được set lên 1

DMA sẽ sinh ra nếu bit DMA dc set lên 1(DMA chỉ có trên ADC1 và ADC3)

Kết quả convert được lưu vào thanh ghi DR

Bắt đầu convert bằng cách set bit ADON lên 1

Cơ chế để tạo ADC như sau:

  1. Enable bộ clock cho ADC, ghi hệ số chia cho ADC prescaler
  2. Chọn các kênh cần chuyển đổi
  3. Chọn chế độ chuyển đổi Sinlge, Continuous, Scan, Discontinuous
  4. Chọn thời gian lấy mẫu (Sampling Time)
  5. Chọn Ngắt hoặc DMA
  6. Start bộ chuyển đổi
  7. Kiểm tra cờ EOC hoặc trong ngắt đọc dữ liệu từ thanh ghi DR về

Cấu hình ADC một kênh trong STM32 CubeMX

Trong bài này chúng ta sẽ sử dụng ADC1 chanel 0 chế độ Single hoặc Continuous để đọc giá trị từ biến trở về.

Đầu tiên các bạn mở phần mềm CubeMX, chọn chip STM32F103C8 và start project.

Trong Sys chọn debug: serial wire các bước này mình đã nói kĩ trong Bài 3 rồi nhé

Tiếp tục trong ADC1 tick chọn Chanel 0

H3 5

Trong configurations chọn như hình.

Giải thích:

  • Data Alignment: Right Align Căn chỉnh data bên phải. Vì thanh ghi dữ liệu là 16 bit, chuyển đổi là 12bit, thanh ghi này sẽ xác định dữ liệu sẽ được căn lề bên trái hoặc phải
  • Scan Mode:Disable. Tắt chế độ quét(Chỉ sử dụng được khi sử dụng nhiều kênh)
  • Continuous mode: Disable . Tắt chế độ làm việc liên tục sẽ là chế độ Single
  • Rank: 1.Mức ưu tiên của kênh (sử dụng khi chuyển đổi nhiều kênh)
  • Samping Time: 239.5 Cycles.Thời gian chuyển đổi tính theo chu kì ADC

Lưu ý: Sampling time càng cao thì chuyển đổi càng chính xác

H4 4

Trong NVIC tick vào bật ngắt ADC1

H5 5

Đặt tên project chọn toolchain và gen code

H6 5

Lập trình ADC một kênh với STM32

Nhấn F7 đê Build project. Trong stm32f1xx_it.c tìm đến hàm xử lý ngắt ADC.

Go to define nó. Hẳn bạn đã rất quen thuộc bước này.

H7 6

Tìm tới hàm HAL_ADC_ConvCpltCallback(hadc), Go to define

H8 5

Coppy và paste vào khu tiền xử lý trước main()

H9 6

Sau đó chúng ta khởi tạo một biến u16_ADCVal lưu giá trị ADC. Trong hàm xử lý ngắt ta điều hướng ngắt, nếu ngắt là ADC1, đọc giá trị ADC vào biến vừa khởi tạo.

Khơi tạo một biến Voltage lưu trữ giá trị điện áp tại chân CH0 để so sánh với thực tế. Volage  =  ADC_Value/4095*3.3

Trong đó 4095 là gía trị cực đại của ADC.

3.3 là điện áp tham chiếu Vref

H10 4

Sau đó khởi động ADC1 bằng lệnh HAL_ADC_Start_IT(&hadc1); trong hàm while(1), de lay khoảng 50 ms mỗi lần đọc.

Vì chế độ single là chế độ đọc một lần vì vậy ta phải liên tục gọi hàm Start, chế độ này sẽ tiết kiệm năng lượng hơn chế độ Cont và phụ thuộc vào lập trình viên khi nào cần dùng sẽ bật.

H11 4

F7 để Build sau đó nạp chương trình, nhấn vào nút debug (Ctr + F5), Add 2 biến u16_ADCVal và Voltage vào.

Nhấn F5 để chạy debug, ta thấy sai số trong khoảng +-0.04V. 

H12 3
H15

Với chế độ Continuous các bạn tìm đến hàm khởi tạo ADC : MX_ADC1_Init()

Chỉnh dòng hadc1.Init.ContinuousConvMode = DISABLE; Thành ENABLE

H13 2

Chuyển hàm HAL_ADC_Start_IT(&hadc1); lên trên While(1)

H14 2

Nhấn F7 Build và nạp vào chip. Vào debug và xem kết quả.

Kết

Lập trình STM32 đọc ADC một kênh là một trong những bài bắt buộc phải nắm rõ trong lập trình STM32. Bởi vì các thiết bị Analog đều cần phải sử dụng ADC để vi điều khiển có thể hiểu được,

Hãy cố gắng làm chủ ADC một kênh nhé

4.5/5 - (4 bình chọn)

12 những suy nghĩ trên “Bài 8: Lập trình STM32 đọc ADC một kênh

  1. Nhân Trần nói:

    Ad hướng dẫn dùm mình 1 tí, mình cần chuyển đổi 1 số thực (float) sang số uint8_t thì dùng hàm gì nhỉ? mình mới nhập môn nên còn gà lắm!

  2. Nhân Trần nói:

    Cụ thể là mình đang làm bài tập đọc ADC, đọc được giá trị điện áp Voltage ( dạng số thực), muốn gửi lên Hercules Teminal để xem giá trị (qua Uart)
    HAL_UART_Transmit(&huart1,Voltage,sizeof(u8_TxBuff),100);
    Mong bạn hướng dẫn giúp ! Cảm ơn .

  3. Van Thanh nói:

    Giả sử mình có một nút nhấn, mà mình muốn lúc nút nhấn không bật thì mới dùng adc thì làm sao ạ ? Mong anh giải đáp, em mới học lập trình nên hơi non.

  4. Tú Huỳnh nói:

    em phải xem video hay đọc bên web khác trước rồi vài đọc lại bài anh viết em mới biết là anh đang viết cái gì ^^.

  5. Thuc nói:

    Chào Thầy Khuê Nguyễn,

    Mình xem bài viết của bạn chạy ADC mô phỏng trên proteus
    Thì giá trị đọc khi vặn biến trở lên mức cao nhất 5v=> thì giá trị hiển thị ra LCD ~6.59(~7v)
    Mình chỉ set up 1 điểm duy nhất khác với bạn Set up là mình để thời gian biến đổi mặc định theo CubeMX cài đặt 1.5 cycles ==> còn các cài đặt khác giống hệt của bạn

    Mình đang thắc mắc đúng ra kéo biến trở lên Max thì cũng chỉ hiển thị tối đa 5V

    Bạn chỉ giúp mình.

  6. Thuc nói:

    Mình tìm ra rồi nguyên nhân rồi,

    Nó ở chỗ tính toán phải chia cho 4096 nó mới ra Max 3.3v
    =>Công thức đúng: Vol = (float)(3.3*ADC_Val/4096);

    Mình chia cho 4095 lên kết quả ra sai số lớn

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *