[研电赛技术支持] 【GD32F303红枫派使用手册】第十三讲 ADC-内部温度传感器和参考电压采样实验

[复制链接]
 楼主| 聚沃科技 发表于 2024-6-12 09:40 | 显示全部楼层 |阅读模式
本帖最后由 聚沃科技 于 2024-6-12 09:45 编辑

红枫派首图.png
13.1 实验内容
本实验是通过ADC注入组采样内部温度传感器和参考电压,通过本实验主要学习以下内容:
内部温度传感器和参考电压简介
• ADC注入组采样配合ADC中断应用
13.2 实验原理
13.2.1 内部温度传感器和参考电压简介
GD32F303有两个内部通道,分别为内部温度传感器(ADC0_CH16)和内部参考电压VrefintADC0_CH17)。
温度传感器可以用来测量器件周围的温度。温度传感器的输出电压随温度线性变化,由于生产过程的多样化,温度变化曲线的偏移在不同的芯片上会有不同(最多相差 45°C)。内部温度传感器更适合于检测温度的变化,而不是测量绝对温度。如果需要测量精确的温度,应该使用一个外置的温度传感器来校准这个偏移错误。
ADC 数据寄存器中读取并计算温度传感器数据 Vtemperature, 并由下面公式计算出实际温度:
温度(℃)=(V25-Vtemperature)/Avgslope+25
V25:温度传感器在 25°C 下的电压,从datasheet中可以查到典型值为1.45V
Avg_Slope:温度与温度传感器电压曲线的均值斜率,从datasheet中可以查到典型值为4.1mV/℃
内部电压参考(VREFINT)提供了一个稳定的(带隙基准)电压输出给 ADC 和比较器,典型值为1.2V
13.3 硬件设计
本实验使用两个内部ADC通道,无需要硬件设计。
13.4 代码解析
13.4.1 中断使能函数
driver_adc.c中定义了开启中断的函数ADC_int_enable
  1. C
  2. /*ADC中断使能函数*/
  3. void ADC_int_enable(typdef_adc_ch_general *ADC)
  4. {
  5.     /*规则组中断使能*/
  6.     if(ADC->adc_channel_group == ADC_REGULAR_CHANNEL)
  7.     {
  8.         adc_interrupt_enable(ADC->adc_port,ADC_INT_EOC);
  9.         adc_interrupt_flag_clear(ADC->adc_port,ADC_INT_EOC);
  10.     }
  11.     /*注入组中断使能*/
  12.     else if(ADC->adc_channel_group == ADC_INSERTED_CHANNEL)
  13.     {
  14.         adc_interrupt_enable(ADC->adc_port,ADC_INT_EOIC);
  15.         adc_interrupt_flag_clear(ADC->adc_port,ADC_INT_EOIC);
  16.     }        
  17. }
13.4.2 ADC中断函数
driver_adc.c中定义了ADC的中断函数driver_adc_int_handler
  1. C
  2. void driver_adc_int_handler(typdef_adc_ch_general *ADC,void *buffer)
  3. {
  4.     uint8_t i;
  5.     if(ADC->adc_channel_group == ADC_REGULAR_CHANNEL)
  6.     {
  7.         if(SET == adc_interrupt_flag_get(ADC->adc_port,ADC_INT_FLAG_EOC))
  8.         {
  9.             adc_interrupt_flag_clear(ADC->adc_port,ADC_INT_FLAG_EOC);
  10.             if(ADC->adc_mode == ADC_DAUL_REGULAL_PARALLEL)
  11.             {
  12.                 REG32(buffer) = (uint32_t)(ADC_RDATA(ADC->adc_port));
  13.             }
  14.             else
  15.             {
  16.                 REG16(buffer) = (uint16_t)(ADC_RDATA(ADC->adc_port));
  17.             }
  18.                
  19.         }
  20.     }
  21.     else if(ADC->adc_channel_group == ADC_INSERTED_CHANNEL)
  22.     {
  23.         if(SET == adc_interrupt_flag_get(ADC->adc_port,ADC_INT_FLAG_EOIC))
  24.         {
  25.             adc_interrupt_flag_clear(ADC->adc_port,ADC_INT_FLAG_EOIC);
  26.             if(ADC->adc_mode == ADC_DAUL_INSERTED_PARALLEL)
  27.             {
  28.                 for(i = 0; i<ADC->ch_count ; i++)
  29.                 {
  30.                     REG32(buffer) = REG32((ADC->adc_port) + 0x3C+(i*4));
  31.                     buffer += 4;
  32.                 }
  33.             }
  34.             else
  35.             {
  36.                 for(i = 0; i<ADC->ch_count ; i++)
  37.                 {
  38.                     REG16(buffer) = REG16((ADC->adc_port) + 0x3C+(i*4));
  39.                     buffer += 2;
  40.                 }
  41.             }
  42.         }
  43.     }
  44.         
  45. }
13.4.3 内部ADC通道结构体定义
ADC的初始化在前两章已经讲述过,这里就介绍下ADC和两个通道的结构体定义:
  1. C
  2. typdef_adc_ch_general  VRef_VTem_ADC = {
  3.     .rcu_adc = RCU_ADC0,//ADC0的时钟
  4.     .adc_psc = RCU_CKADC_CKAPB2_DIV6,//ADC0设置为APB2 6分频
  5.     .adc_port = ADC0,//ADC口为ADC0
  6.     .adc_mode = ADC_MODE_FREE,//ADC模式为独立模式
  7.     .adc_channel_group = ADC_INSERTED_CHANNEL,//使用注入组
  8.     .adc_scan_function = ENABLE,//开启扫描模式
  9.     .adc_continuous_function = DISABLE,//关闭循环模式,因为使用的是注入组,故该参数实际无效
  10.     .ch_count = 2,//转换长度为2
  11.     .trigger_source = ADC0_1_2_EXTTRIG_INSERTED_NONE,
  12.     .DMA_mode = DISABLE//不使用DMA
  13. };

  14. typdef_adc_ch_parameter VRef_VTem_ch_parameter[2] =
  15. {
  16.     {
  17.         .rcu_port = NULL,
  18.         .port = NULL,
  19.         .pin = NULL,
  20.         .gpio_speed = NULL,
  21.         .adc_channel = ADC_CHANNEL_16,//通道16
  22.         .sample_time = ADC_SAMPLETIME_55POINT5//设置采样周期为55.5
  23.     }
  24.     ,
  25.     {
  26.         .rcu_port = NULL,
  27.         .port = NULL,
  28.         .pin = NULL,
  29.         .gpio_speed = NULL,
  30.         .adc_channel = ADC_CHANNEL_17,//通道17
  31.         .sample_time = ADC_SAMPLETIME_55POINT5,//设置采样周期为55.5
  32.     }

  33. };
需要说明的是,由于使用的是内部通道,无需配置外部IO口,所以rcu_port参数等无需设置,这里是为了方便读者阅读将这几个参数设置为了NULL
13.4.4 内部通道ADC配置
bsp_adc.c中定义了内部通道ADC配置的函数bsp_Vref_Vtemp_ADC_config
  1. C
  2. void bsp_Vref_Vtemp_ADC_config()
  3. {
  4.     /*ADC配置*/
  5.     driver_adc_config(&VRef_VTem_ADC,VRef_VTem_ch_parameter);
  6.     /*ADC中断打开*/
  7.     ADC_int_enable(&VRef_VTem_ADC);
  8.     /*NVIC设置*/
  9.     nvic_irq_enable(ADC0_1_IRQn,0,0);
  10. }
13.4.5 中断入口函数
gd32f30x_interrupt.c中定义了中断入口函数:
  1. C
  2. uint16_t Vref_Vtemp_data[2] ;
  3. void ADC0_1_IRQHandler()
  4. {
  5.     driver_adc_int_handler(&VRef_VTem_ADC,(uint16_t *)Vref_Vtemp_data);
  6. }
13.4.6 main函数实现
  1. C
  2. int main(void)
  3. {
  4.     delay_init();//delay函数初始化
  5.     bsp_uart_init(&BOARD_UART);//BOARD_UART串口初始化
  6.     bsp_Vref_Vtemp_ADC_config();//内部通道ADC配置和中断使能
  7.     while (1)
  8.     {
  9.         driver_adc_software_trigger_enable(&VRef_VTem_ADC);        //软件触发ADC
  10.         delay_ms(1000);
  11.         temperature = (1.45 - Vref_Vtemp_data[0]*3.3/4095) * 1000 / 4.1 + 25;        /*内部温度ADC转换值转换为实际温度值*/
  12.         vref_value = (Vref_Vtemp_data[1] * 3.3 / 4095);        /*内部参考电压ADC转换值转换为实际电压值*/               
  13.         printf(" the temperature data is %2.0f degrees Celsius\r\n", temperature);        /*打印实际温度值*/
  14.         printf(" the reference voltage data is %5.3fV \r\n", vref_value);        /*打印内部参考实际电压值*/
  15.     }
  16. }
本例程main函数首先进行了延时函数初始化,为了演示实验结果,这里初始化了BOARD_UART串口,关于串口的使用,请读者参考串口章节,然后是内部通道ADC的配置和中断使能。在主循环中,先出发一次内部通道ADC,然后延时1s,在延时过程中ADC转换结束会进入ADC中断函数,中断函数将两个注入组通道数据赋给Vref_Vtemp_data数组,延时结束后,对温度和内部电压进行计算并将计算结果打印出来。
13.5 实验结果
使用USB-TypeC线,连接电脑和板上USB to UART口后,配置好串口调试助手,即可看到内部温度传感器测到的温度值以及内部参考电压值了。
图片1.png 图片2.png

本教程由GD32 MCU方案商聚沃科技原创发布,了解更多GD32 MCU教程,关注聚沃科技官网,GD32MCU技术交流群:859440462

您需要登录后才可以回帖 登录 | 注册

本版积分规则

170

主题

190

帖子

13

粉丝
快速回复 在线客服 返回列表 返回顶部

170

主题

190

帖子

13

粉丝
快速回复 在线客服 返回列表 返回顶部