GD32F103VE使用软件扫描读取多通道AD值。
GD32F103的ADC为12位AD转换器,ADC转换结果保存在16位数据寄存器中;
模拟输入通道:
16个外部模拟输入通道;
1个内部温度传感器通道(Vsense)
1个内部参考电压输入通道(VrefInt)
ADC的VDDA电源引脚需要接入3.3V;
ADC输入模拟量的范围:Vref- 至Vref+之间;
注意:ADC同时使用"规则组通道"和"注入组通道",则"注入组通道"的采样周期不能1.5和7.5个采样周期;
ADC0_CH16为温度传感器通道,Internal temperature sensor output voltage;
ADC0_CH17为内部参考电压通道,Internal voltage reference output voltage;
Vref-引脚必须连接至VSSA引脚,Vref+连接到VDDA,但在64脚以下的CPU(含64脚),其Vref+和Vref-已经在内部连接至VDDA和VSSA;
注意:ST和GD的手册里都写着不同芯片最大偏差45度
#include "ADC.h"
#include "delay.h"
#include "stdio.h" //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()
/*
GD32F103的ADC为12位AD转换器,ADC转换结果保存在16位数据寄存器中;
模拟输入通道:
16个外部模拟输入通道;
1个内部温度传感器通道(Vsense)
1个内部参考电压输入通道(VrefInt)
触发转换:
软件触发;
硬件触发;
转换模式:
单通道转换或多通道扫描转换;
单次模式,选择指定的模拟输入通道后,触发一次,则转换一次;
连续模式,选择指定的模拟输入通道后,连续进行AD转换;用于DMA
同步模式,当同时使用ADC0,ADC1和ADC2时,这3个设备就可以同时进行AD转换;
间断模式;
ADC的VDDA电源引脚需要接入3.3V;
ADC输入模拟量的范围:Vref- 至Vref+之间;
ADC_RSQ0~ADC_RSQ2寄存器规定了"规则组通道"的选择;
ADC_RSQ0的RL[3:0]用来指定"规则通道组"转换序列的长度,即"规则通道组"选择;
连续进行AD转换的通道总数为(RL[3:0]+1),在DMA传输中要知道有多少个通道参与AD转换
ADC_ISQ寄存器规定了"注入组通道"的选择;
ADC_ISQ0的IL[3:0]用来指定"整个注入通道组"转换序列的长度,即"规则通道组"选择
连续进行AD转换的通道总数为(IL[3:0]+1),在DMA传输中要知道有多少个通道参与AD转换
注意:ADC同时使用"规则组通道"和"注入组通道",则"注入组通道"的采样周期不能1.5和7.5个采样周期;
ADC0_CH16为温度传感器通道,Internal temperature sensor output voltage;
ADC0_CH17为内部参考电压通道,Internal voltage reference output voltage;
Vref-引脚必须连接至VSSA引脚,Vref+连接到VDDA,但在64脚以下的CPU(含64脚),其Vref+和Vref-已经在内部连接至VDDA和VSSA;
注意:ST和GD的手册里都写着不同芯片最大偏差45度
*/
void InternalTemperatureSensor_Init(void);
void Read_TemperatureValue(void);
void Read_InternalVoltageValue(void);
uint16_t ADC_Read(uint8_t channel);
void InternalTemperatureSensor_Init(void)
{
rcu_periph_clock_enable(RCU_ADC0);//使能ADC0时钟
rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV8);
//配置ADC时钟8分频
//由于ADC最大时钟频率为14MHz,经过8分频后,变为1.75MHz
adc_tempsensor_vrefint_enable();
//channel 16 and 17 enable of ADC0
//使能温度传感器通道和内部参考电压通道
//ADC工作模式配置//
adc_mode_config(ADC_MODE_FREE);//只使用一个ADC,属于独立模式
adc_special_function_config(ADC0,ADC_SCAN_MODE,ENABLE);//若ADC0使用的是多通道,则配置ADC0为扫描模式
// adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);//若ADC0使用的是单通道,则配置ADC0为连续转换模式
adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);//ADC转换结果转换右对齐
adc_channel_length_config(ADC0,ADC_REGULAR_CHANNEL,1);
//连续进行AD转换的通道总数为1,在DMA传输中要知道有多少个通道参与AD转换
//只扫描一个通道
adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE);
//使用软件触发AD转换
adc_external_trigger_config(ADC0,ADC_REGULAR_CHANNEL,ENABLE);
//使能ADC规则通道组外部触发,enable ADC regular channel group external trigger
adc_enable(ADC0);//使能ADC0
delay_ms(10); //等待1ms
adc_calibration_enable(ADC0);//等待ADC0校准完成
}
//函数功能:读取ADC0通道号为channel的AD值
uint16_t ADC_Read(uint8_t channel)
{
uint16_t adcValue = 0;
adc_regular_channel_config(ADC0,0,channel,ADC_SAMPLETIME_239POINT5);
//将ADC0中channel通道放在第0位置优先进行AD转换,采样时间为239.5个时钟周期
adc_software_trigger_enable(ADC0,ADC_REGULAR_CHANNEL);
//触发ADC0设备执行1次AD转换
while(!adc_flag_get(ADC0,ADC_FLAG_EOC))//等待"ADC0转换标志"建立
{
}
adc_flag_clear(ADC0, ADC_FLAG_EOC);//清除"ADC0转换标志"
adcValue = adc_regular_data_read(ADC0);//读取ADC0数据
return adcValue;
}
/*
温度(°C) = {(V25 - VSENSE) / Avg_Slope} + 25
V25 = VSENSE在25°C时的数值,这里取1.43V
Avg_Slope = 温度与VSENSE曲线的平均斜率,4.3mV/°C
即:(1.43 - voltage) / 0.0043 + 25;
*/
void Read_TemperatureValue(void)
{
float f;
uint16_t tmp;
tmp = ADC_Read(ADC_CHANNEL_16); //读取ADC0通道16的AD值
printf("\r\nADC0_16: %d ", tmp);
f = tmp;f = f * 3.3;f = f / 4096; //转换成电压值单位为V
printf("\r\nADC0_16_Voltage: %0.3fV", f);
f = V25 -f;f =f / AvgSlope;f= f+25; //计算温度值
printf("\r\nTmoerature: %0.1f\r\n", f);
}
void Read_InternalVoltageValue(void)
{
float f;
uint16_t tmp;
tmp = ADC_Read(ADC_CHANNEL_17); //读取ADC0通道17的AD值
printf("\r\nADC0_17: %d ", tmp);
f = tmp;f = f * 3.3;f = f / 4096; //转换成电压值单位为V
printf("\r\nInternalVoltage: %0.3fV\r\n", f);
}
#ifndef __ADC_H
#define __ADC_H
#include "gd32f10x.h" //使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,int16_t,int32_t,int64_t
#define V25 1.430 //V
#define AvgSlope 0.0043 //V/°C
extern void InternalTemperatureSensor_Init(void);
extern void Read_TemperatureValue(void);
extern void Read_InternalVoltageValue(void);
#endif
main.c如下:
#include "gd32f10x.h" //使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,int16_t,int32_t,int64_t
#include "delay.h"
#include "UART3.h"
#include "stdio.h" //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()
#include "ADC.h"
uint16_t volValue = 0;
const char CPU_Reset_REG[]="\r\nCPU reset!\r\n";
int main(void)
{
//NVIC_PRIGROUP_PRE4_SUB0:抢占优先级为4bit(取值为0~15),子优先级为0bit(没有响应优先级)
//NVIC_PRIGROUP_PRE3_SUB1:抢占优先级为3bit(取值为0~7),子优先级为1bit(取值为0~1)
//NVIC_PRIGROUP_PRE2_SUB2:抢占优先级为2bit(取值为0~3),子优先级为2bit(取值为0~3)
//NVIC_PRIGROUP_PRE1_SUB3:抢占优先级为1bit(取值为0~1),子优先级为3bit(取值为0~7)
//NVIC_PRIGROUP_PRE0_SUB4:抢占优先级为0bit(没有抢占优先级),子优先级为3bit(取值为0~15)
nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);//设置系统中断优先级"抢占优先级为4bit,子优先级为0bit"
delay_init();
INTX_ENABLE();//开启所有中断
UART3_Init(115200);//初始化UART3
printf("%s",CPU_Reset_REG);//调试串口输出"\r\nCPU reset!\r\n"
InternalTemperatureSensor_Init();
while(1)
{
Read_TemperatureValue();
Read_InternalVoltageValue();
delay_ms(500);
}
}