การใช้งานของ ADC ใน CH32V003 นั้นมีการทำงานหลายแบบมาก บทความนี้จะมาสรุปเกี่ยวกับ วิธีการใช้งาน ADC และ ประเภทของ ADC สำหรับการใช้งาน เรามาดูภาพรวม และ แนวทางการใช้งานกันเลย
1. โหมดการทำงานของ ADC ใน CH32V003
CH32V003 มี ADC แบบ 10-bit ความละเอียด รองรับการทำงานได้ 3 แบบหลัก ๆ:
| โหมด | การทำงาน | การใช้งาน |
|---|---|---|
| Single Conversion Mode | แปลงสัญญาณแค่ครั้งเดียว เมื่อถูกสั่ง (Software Trigger) หรือ Hardware Trigger | อ่านค่า ADC ทีละตัว |
| Continuous Conversion Mode | ทำการแปลง ADC ต่อเนื่องไม่หยุดจนกว่าจะสั่งหยุด | ใช้วัดค่า real-time ต่อเนื่อง เช่น เซ็นเซอร์อุณหภูมิ |
| Scan Mode (Multiple Channel) | อ่านหลายช่องสัญญาณตามลำดับอัตโนมัติ | วัดหลาย input เช่น sensor หลายตัว |
หมายเหตุ:
- ช่อง ADC Input (Analog Inputs) มีทั้งหมด 8 ช่อง คือ AIN0-AIN7
- รองรับทั้ง Trigger ภายนอก (จาก Timer เป็นต้น) และ Trigger ภายใน (Software)
2. ขั้นตอนการทำงานของ ADC ใน MCU
ลำดับการทำงานของ ADC โดยทั่วไป เป็นดังนี้:
- เปิด Clock ของ ADC
เปิดใช้งาน Clock ผ่าน RCC ก่อน (RCC_APB2PeriphClockCmd) - Configure ADC Parameters
ตั้งค่า ADC ด้วยโครงสร้างADC_InitTypeDef- โหมด (Single, Continuous, Scan)
- Alignment (Right/Left)
- External Trigger
- จำนวน Channels ที่ต้องแปลง
- Configure ADC Channels
เลือก Channel ที่ต้องการอ่าน และกำหนดลำดับ - Enable ADC
เปิดการทำงาน ADC (ADC_Cmd(ADCx, ENABLE)) - Calibration (เฉพาะบางกรณี)
รีเซ็ต และเริ่มการปรับเทียบค่าภายใน ADC - Start Conversion
สั่งเริ่มต้นการแปลง ADC (ADC_SoftwareStartConvCmd) - Wait Until Conversion Complete
เช็คสถานะEOC(End of Conversion) Flag - Read Data
อ่านค่าผลลัพธ์จาก Register (ADC_GetConversionValue)
3. โค้ดตัวอย่างการเขียนโปรแกรมใช้งาน ADC
#include "ch32v00x_adc.h"
#include "ch32v00x_rcc.h"
void ADC1_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // เปิด clock ADC1
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // ทำงานแบบอิสระ
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // ไม่ scan หลาย channel
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // เปิดการทำงานต่อเนื่อง
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // ไม่มี trigger ภายนอก
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // ชิดขวา
ADC_InitStructure.ADC_NbrOfChannel = 1; // ใช้แค่ 1 channel
ADC_Init(ADC1, &ADC_InitStructure); // ตั้งค่า ADC1
ADC_Cmd(ADC1, ENABLE); // เปิดใช้งาน ADC1
ADC_ResetCalibration(ADC1); // รีเซ็ตการ calibrate
while(ADC_GetResetCalibrationStatus(ADC1)); // รอ reset calibration เสร็จ
ADC_StartCalibration(ADC1); // เริ่ม calibration
while(ADC_GetCalibrationStatus(ADC1)); // รอ calibration เสร็จ
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); // ตั้ง channel 0 เป็นตัววัด
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // เริ่มสั่งแปลง
}
uint16_t ADC1_Read(void)
{
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); // รอแปลงเสร็จ
return ADC_GetConversionValue(ADC1); // อ่านค่า
}
4. คำอธิบายฟังก์ชัน (Line-by-Line Explanation)
void ADC1_Init(void)
{
ADC_InitTypeDef ADC_InitStructure; // สร้างโครงสร้างเก็บค่าตั้งค่า ADC
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); // เปิด clock ของ ADC1
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // เลือกโหมดอิสระ
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // ไม่ต้อง scan หลาย channel
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // เปิด continuous mode
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // ไม่มี external trigger
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // ชิดขวา (ค่าที่อ่านได้เหมือนเป็น unsigned)
ADC_InitStructure.ADC_NbrOfChannel = 1; // ใช้แค่ 1 channel
ADC_Init(ADC1, &ADC_InitStructure); // ส่งข้อมูลเข้าไปยัง ADC1
ADC_Cmd(ADC1, ENABLE); // เปิดใช้งาน ADC1
ADC_ResetCalibration(ADC1); // รีเซ็ตการตั้งค่า calibration
while(ADC_GetResetCalibrationStatus(ADC1)); // รอจนกว่าการรีเซ็ต calibration จะเสร็จสิ้น
ADC_StartCalibration(ADC1); // เริ่มต้นกระบวนการ calibration ใหม่
while(ADC_GetCalibrationStatus(ADC1)); // รอ calibration เสร็จ
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); // ตั้งให้ใช้ช่อง 0
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // เริ่มแปลงข้อมูล ADC แบบ software trigger
}
uint16_t ADC1_Read(void)
{
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); // รอ flag End of Conversion
return ADC_GetConversionValue(ADC1); // อ่านค่า ADC
}
5. ประเภทการอ่านค่า ADC
- Single Read: สั่งแปลงทุกครั้งที่ต้องการค่าใหม่
- Auto Continuous: เริ่มแค่ครั้งเดียว จากนั้นอ่านค่าใหม่ได้ตลอดเวลา
- Trigger-based: เริ่มแปลงเมื่อตรงกับสัญญาณ Trigger ภายนอก เช่น Timer Event
6. การใช้ DMA ร่วมกับ ADC
- CH32V003 รองรับ การใช้ DMA อ่านค่าจาก ADC อัตโนมัติ
- ไม่ต้องรอค่าสำเร็จจาก EOC flag
- ใช้
ADC_DMACmd(ADCx, ENABLE);เพื่อเปิดโหมด DMA
สรุปสั้น ๆ แบบภาพรวม
| หมวด | รายละเอียด |
|---|---|
| จำนวน Channel | 8 ช่อง (AIN0-AIN7) |
| ความละเอียด | 10-bit |
| แหล่ง Trigger | Software / Timer |
| รองรับ DMA | มี |
| ความเร็ว Sampling | ขึ้นอยู่กับ Clock (สูงสุด 24MHz สำหรับ ADC Clock) |
| ฟังก์ชันสำคัญ | ADC_Init, ADC_Cmd, ADC_SoftwareStartConvCmd, ADC_GetConversionValue, ADC_DMACmd |
