• HC32_HC32F072FAUA_内部温度传感器+外部输入_ADC多通道采集


    吐槽写在前面

    不知道是我的使用方法不对,还是华大这个内部温度传感器是真的难用。反正我现在认为华大的MCU设计还是有待提高。下面的内容,如果有华大的技术人员看到了,劳烦你解释一下原因或者更优的解决办法。

    起因是我的应用电路里面,有一路ADC需要MCU采集, 同时,我还需要使用MCU内部温度传感器。 虽然MCU的内部温度传感器是内部的,但可以说我有两路ADC需要采集。也可以说我有多路ADC需要采集。  我使用ADC的单次模式,只对内部温度传感器通道采集温度,是没有问题的,已经用红外热像仪检验过了。

    之前我用驱动库example里面的,顺序扫描模式和插队扫描模式,得到的温度采集通道结果都不对(超过100℃大得离谱,反正正常智商都能判断结果是不对的)。

    我原本以为是顺序扫描和插队扫描这扫描模式本身的问题。所以我尝试用单次模式实现多通道的读取。(思路是:我每次只采集一次,转换完把数据读取之后,我把单次采集的通道号换成另一个需要采集的通道。然后再去采集。)

    但是我发现,结果和两种扫描模式的结果并无不同。 也就是说温度值不对,与ADC的单次模式与扫描模式本身是无关的。

    ------------------------------------------

    卡了很久,苦思不得其解。 后面尝试调整ADC配置的两个参数,才逐步找到问题。

    第一个参数是 ADC采样分频, 它只有4个选项:

    我选择了8分频

    第二个采样参数是ADC采样周期,它也只有4个选项

    我选择 12个转换周期。

    经过上述的ADC控制参数的调整,温度的测量结果 和 使用单次采样模式只测量温度时已经接近了,但还是存在大约3℃的偏差。  从上面的调参来看,我把采样的时间调长一点,温度的测量就会越准确。 那么问题就可以确定在采样时长上了。

    为了更准确, 我把MCU的PCLK再次调低。 发现此时的温度测量 和 使用单次采样模式只测量温度时的测量结果就一致了。

    ------------------------------------------

    按理说这个问题已经解决了, 为什么存在本文开篇的吐槽呢。

    就是当我降低了PCLK主频之后, 串口通信不正常了, 115200的波特率已经不支持了。I2C的通信也不正常了, 1000000的波特率也不支持了。如果产品没有要求115200的通信波特率也就罢了, 产品甚至要求更高的230400的波特率。那么此次就出现了矛盾, 我必须在内部温度传感器 与 串口之间做一个折衷选择。这怎么选?

    还是说,我的解决思路有问题,那么请华大的技术人员给点建议,谢谢。

    ------------------------------------------

    下面先给出目前使用单次采样模式的多通道采样程序,这东西还是有参考价值的。

    使用顺序扫描和插队扫描应该也能实现的,参考驱动与例子库的 example。

    main.c

    1. #include "ddl.h"
    2. #include "uart.h"
    3. #include "gpio.h"
    4. #include "dac.h"
    5. #include "flash.h"
    6. #include "i2c.h"
    7. #include "user_gpio.h"
    8. #include "user_uart.h"
    9. #include "user_dac.h"
    10. #include "user_adc.h"
    11. #include "user_i2c.h"
    12. #include "execute_pc_cmd.h"
    13. #include "execute_fpga_cmd.h"
    14. uint8_t Whoiam;
    15. uint8_t i2cdata;
    16. en_result_t I2CRet = Error;
    17. float Vapd = 0.0;
    18. int16_t DAC_OUT_TEMP = 0;
    19. int32_t main(void)
    20. {
    21. sys_clk_init();
    22. user_apdgpio_init();
    23. user_uart_init();
    24. user_dac_init();
    25. user_adc_init();
    26. user_i2c_init();
    27. kx023_1025_config();
    28. apd_enable();
    29. while(Ok != Flash_Init(1, TRUE)){
    30. ;
    31. }
    32. while(1)
    33. {
    34. if(FpgaRxQueue.size > 0){
    35. QueuePop(&FpgaRxQueue, fpgaRx);
    36. fpgaRxFlag = 1;
    37. }
    38. if(PcRxQueue.size > 0){
    39. QueuePop(&PcRxQueue, pcRx);
    40. pcRxFlag = 1;
    41. }
    42. if(fpgaRxFlag == 1){
    43. fpga_cmd_ret = execute_fpga_cmd();
    44. // send_data_to_fpga(fpgaRx, 8);
    45. fpgaRxFlag = 0;
    46. }
    47. if(pcRxFlag ==1 ){
    48. pc_cmd_ret = execute_pc_cmd();
    49. //send_data_to_pc(pcRx, 8);
    50. pcRxFlag = 0;
    51. }
    52. user_apd_output_set(140);
    53. get_apd_adc(); // ▲ 重点是这
    54. get_temperature_adc(); // ▲ 和这
    55. kx023_1025_read();
    56. send_data_to_pc(angle_data,8);
    57. delay1ms(1);
    58. }
    59. }

    user_adc.c

    1. #include "user_adc.h"
    2. #include "gpio.h"
    3. #include "bgr.h"
    4. #include "adc.h"
    5. uint8_t ADC_UNIT = ERROR_UNIT;
    6. uint8_t ADC_FLAG = ADC_WAITING;
    7. uint16_t Trim = 0;
    8. uint32_t u32AdcRestult0;
    9. uint32_t u32AdcRestultTemperature;
    10. float Vapd_sense = 0;
    11. float temperature = 0;
    12. // ADC端口 配置
    13. void adc_gpio_config(void)
    14. {
    15. Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE); // 开启ADC/BGR GPIO外设时钟
    16. Gpio_SetAnalogMode(GpioPortA, GpioPin0); // PA00 (AIN0)
    17. }
    18. // ADC模块 初始化
    19. void adc_config(void)
    20. {
    21. stc_adc_cfg_t stcAdcCfg;
    22. DDL_ZERO_STRUCT(stcAdcCfg);
    23. // 开启ADC/BGR外设时钟
    24. Sysctrl_SetPeripheralGate(SysctrlPeripheralAdcBgr, TRUE);
    25. Bgr_BgrEnable(); // 开启BGR
    26. Bgr_TempSensorEnable(); // 【开启温度传感器】
    27. // ADC 初始化配置
    28. stcAdcCfg.enAdcMode = AdcSglMode; // 采样模式-单次
    29. stcAdcCfg.enAdcClkDiv = AdcMskClkDiv8; // 采样分频-1
    30. stcAdcCfg.enAdcSampCycleSel = AdcMskSampCycle12Clk; // 采样周期数-12
    31. stcAdcCfg.enAdcRefVolSel = AdcMskRefVolSelInBgr2p5; // 参考电压选择-内部2.5V
    32. stcAdcCfg.enAdcOpBuf = AdcMskBufEnable; // OP BUF配置-开
    33. stcAdcCfg.enInRef = AdcMskInRefEnable; // 内部参考电压使能-开 AdcMskInRefDisable AdcMskInRefEnable
    34. stcAdcCfg.enAdcAlign = AdcAlignRight; // 转换结果对齐方式-右
    35. Adc_Init(&stcAdcCfg);
    36. }
    37. // ADC 温度单次采样模式 配置
    38. void get_temperature_adc(void)
    39. {
    40. Adc_CfgSglChannel(AdcAiTsInput);
    41. // 启动单次转换采样
    42. Adc_SGL_Start();
    43. ADC_FLAG = ADC_WAITING;
    44. while(ADC_FLAG == ADC_WAITING){
    45. if(TRUE == Adc_GetIrqStatus(AdcMskIrqSgl))
    46. {
    47. Adc_ClrIrqStatus(AdcMskIrqSgl); ///< 清除中断标志位
    48. u32AdcRestultTemperature = Adc_GetSglResult();
    49. Trim = *((uint16_t *)(0x00100C36));
    50. temperature = 25 + 0.2135 * (float)(u32AdcRestultTemperature - Trim );
    51. ADC_FLAG = ADC_COMPLETED;
    52. // Adc_SGL_Stop(); ///< ADC 单次转换停止
    53. }
    54. }
    55. }
    56. // ADC 温度单次采样模式 配置
    57. void get_apd_adc(void)
    58. {
    59. Adc_CfgSglChannel(AdcExInputCH0);;
    60. // 启动单次转换采样
    61. Adc_SGL_Start();
    62. ADC_FLAG = ADC_WAITING;
    63. while(ADC_FLAG==ADC_WAITING){
    64. if(TRUE == Adc_GetIrqStatus(AdcMskIrqSgl))
    65. {
    66. Adc_ClrIrqStatus(AdcMskIrqSgl); ///< 清除中断标志位
    67. u32AdcRestult0 = Adc_GetSglResult();
    68. Vapd_sense = (float)u32AdcRestult0*0.054267632; // 2.5V内部参考电压
    69. ADC_FLAG = ADC_COMPLETED;
    70. // Adc_SGL_Stop(); ///< ADC 单次转换停止
    71. }
    72. }
    73. }
    74. void user_adc_init(void){
    75. adc_gpio_config();
    76. adc_config();
    77. }

    user_adc.h

    1. #ifndef _USER_ADC_H_
    2. #define _USER_ADC_H_
    3. #include "ddl.h"
    4. #define ERROR_UNIT 0
    5. #define TEMPERATURE_UNIT 1
    6. #define APD_UNIT 2
    7. #define ADC_WAITING 0
    8. #define ADC_COMPLETED 1
    9. extern float temperature;
    10. extern float Vapd_sense;
    11. extern uint8_t ADC_UNIT;
    12. extern uint8_t ADC_FLAG;
    13. void adc_gpio_config(void);
    14. void adc_config(void);
    15. void user_adc_init(void);
    16. void get_temperature_adc(void);
    17. void get_apd_adc(void);
    18. #endif

    2022-12-05:

    华大技术支持今天到我司进行交流, 内部测温的问题解决了,我们不用降主频, 把ADC 8分频之后,等待周期换成12个cycle。在单次采集的时候, 切换通道之后等待10ms或者更少的时间。  温度测量值就是正确的。

    1. // ADC 温度单次采样模式 配置
    2. void get_temperature_adc(void)
    3. {
    4. Adc_CfgSglChannel(AdcAiTsInput);
    5. delayms(10); // 这里做个延迟

     感谢您的阅读,欢迎留言讨论、收藏、点赞、分享。

  • 相关阅读:
    当下、百年之计与蝼蚁一生——读《原则2 :应对变化中的世界秩序》(下)...
    StringBuffer和StringBuilder的区别与联系
    下一代英伟达H100 GPU发布时,国产芯片能追上吗?
    Linux 脚本 hive脚本
    java毕业设计-篮球资讯网站-源码+lw文档+mybatis+系统+mysql数据库+调试
    伦敦银最新均线分析系统怎么操作?
    162_Power Query 快速合并文件夹中表格之自定义函数 TableXlsxCsv_2.0
    rabbitMQ rascal/amqplib报错 Error: Unexpected close 排查
    C++——map和set
    算法与数据结构(二)————入门问题(最大利益问题)
  • 原文地址:https://blog.csdn.net/heqiunong/article/details/126499812