【GD32L233C-START评测】11.DAC输出电压值_ADC读取外部电压值
[复制链接]
本帖最后由 hehung 于 2022-2-12 14:25 编辑
之前的帖子可以参考:
【GD32L233C-START评测】1.开箱
【GD32L233C-START评测】2.手把手创建新工程
【GD32L233C-START评测】3.移植FreeRTOS到GD32L233
【GD32L233C-START评测】4. 移植RT-Thread到GD32L233
【GD32L233C-START评测】5. IIC驱动OLED
【GD32L233C-START评测】6. 获取RTC时间并通过OLED显示
【GD32L233C-START评测】7. PWM驱动LED
【GD32L233C-START评测】8. TRNG真随机数生成
【GD32L233C-START评测】9. CRC检验
【GD32L233C-START评测】10. ADC读取芯片内部温度
本帖讲解将如何使用DAC模块输出电压值并通过ADC模块外部引脚会读DAC输出的电压值。
本来是想专门一个章节用来描述如何使用ADC的外部引脚来读取电压值的,但是呢,手头没有一个传感器是模拟电压输出的,不能进行验证,怎么办呢?
我想到可以使用单片机的DAC模块来输出电压值,然后用ADC外部引脚来会读不就可以了嘛,说干就干。
一、模拟端口查询
我们看GD32L233C开发板上模拟引脚是PA1-PA5,对应的ADC通道为1-5,可以在数据手册中查到,如下:
二、ADC模块
ADC模块在上一篇贴已经有了初步的了解,不同的是这篇帖子使用的是外部引脚。
ADC使用软件触发,12位宽度采样。
使用PA1-ADC的通道1来做采样通道。
三、DAC模块使用
见用户手册14. 数模转换器( 数模转换器(DAC )
同样适用12位宽度,软件触发,不使用缓冲。
使用DAC输出通道,即PA4-DAC_OUT来做模拟电压输出通道,如下图:
四、代码编辑
1. 时钟初始化
初始化需要初始化GPIOA时钟,ADC时钟,APH时钟,DAC时钟
void rcu_config(void)
{
/* enable GPIOC clock */
rcu_periph_clock_enable(RCU_GPIOA);
/* enable ADC clock */
rcu_periph_clock_enable(RCU_ADC);;
/* config ADC clock */
rcu_adc_clock_config(RCU_ADCCK_APB2_DIV6);
/* enable DAC clock */
rcu_periph_clock_enable(RCU_DAC);
}
2. GPIO时钟
void gpio_config(void)
{
/* config the GPIO as analog mode */
gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_1 | GPIO_PIN_4);
}
3. ADC初始化
void adc_config(void)
{
/* ADC data alignment config */
adc_data_alignment_config(ADC_DATAALIGN_RIGHT);
/* ADC channel length config */
adc_channel_length_config(ADC_REGULAR_CHANNEL, 1U);
/* ADC trigger config */
adc_external_trigger_source_config(ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_NONE);
/* ADC external trigger config */
adc_external_trigger_config(ADC_REGULAR_CHANNEL, ENABLE);
/* enable ADC interface */
adc_enable();
delay_1ms(1U);
/* ADC calibration and reset calibration */
adc_calibration_enable();
}
4. ADC读取
uint16_t adc_channel_sample(uint8_t channel)
{
/* ADC regular channel config */
adc_regular_channel_config(0U, channel, ADC_SAMPLETIME_7POINT5);
/* ADC software trigger enable */
adc_software_trigger_enable(ADC_REGULAR_CHANNEL);
/* wait the end of conversion flag */
while(!adc_flag_get(ADC_FLAG_EOC));
/* clear the end of conversion flag */
adc_flag_clear(ADC_FLAG_EOC);
/* return regular channel sample value */
return (adc_regular_data_read());
}
5. DAC初始化
void dac_config(void)
{
dac_deinit();
/* output buffer config */
dac_output_buffer_enable();
dac_output_buffer_disable();
/* trigger config */
dac_trigger_source_config(DAC_TRIGGER_SOFTWARE);
/* dac enable */
dac_enable();
/* enable software trigger */
dac_software_trigger_enable();
}
6. 输出DAC模拟电压值
DAC电压使用数字来表示,因为是12bit,最大值为4096.
从0开始输出,每一秒钟加100,大于4096之后从0开始从新输出电压值。
if(dac_value > DAC_VALUE_MAX)
{
dac_value = 0;
}
else
{
dac_value += 100;
}
/* output data config */
dac_data_set(DAC_ALIGN_12B_R, dac_value);
7. 阅读输出的模拟电压值并通过串口输出
/* read adc value */
adc_value = adc_channel_sample(ADC_CHANNEL_1);
printf("read dac value:%d,voltage:%.2f\r\n", adc_value, dac_value/4096.0*3.3);
8.main函数
int main(void)
{
/* system clocks configuration */
rcu_config();
/* systick configuration */
systick_config();
/* USART configuration */
gd_eval_com_init(EVAL_COM);
/* GPIO configuration */
gpio_config();
/* ADC configuration */
adc_config();
/* configure the DAC */
dac_config();
dac_value = 0;
while(1) {
if(dac_value > DAC_VALUE_MAX)
{
dac_value = 0;
}
else
{
dac_value += 100;
}
/* output data config */
dac_data_set(DAC_ALIGN_12B_R, dac_value);
printf("output dac value:%d, voltage:%.2f\r\n",dac_value, dac_value/4096.0*3.3);
/* read adc value */
adc_value = adc_channel_sample(ADC_CHANNEL_1);
printf("read dac value:%d,voltage:%.2f\r\n", adc_value, dac_value/4096.0*3.3);
printf("---\r\n");
delay_1ms(1000);
}
}
8. 使用大全局变量与宏定义
#define DAC_VALUE_MAX (4096)
uint16_t adc_value;
uint16_t dac_value;
五、效果演示
如上所说,使用PA4输出模拟电压值0-3.3V,对于数字为0-4095。
使用PA1来读取模拟电压值,所以需要将PA4与PA1连接在一起,
PA1 ---- PA4
如下图:
效果如下:
可以看到输出的模拟电压值和读取的模拟电压值有几个数值的差值,但是换成电压之后,取两位小数之后输出的模拟电压和采集的电压基本相同,精度还是很高的,可以满足绝大部分场合的使用要求。
|