การใช้งานของ 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 | 
