吐槽写在前面
不知道是我的使用方法不对,还是华大这个内部温度传感器是真的难用。反正我现在认为华大的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
- #include "ddl.h"
- #include "uart.h"
- #include "gpio.h"
- #include "dac.h"
- #include "flash.h"
- #include "i2c.h"
-
- #include "user_gpio.h"
- #include "user_uart.h"
- #include "user_dac.h"
- #include "user_adc.h"
- #include "user_i2c.h"
-
- #include "execute_pc_cmd.h"
- #include "execute_fpga_cmd.h"
-
-
- uint8_t Whoiam;
- uint8_t i2cdata;
- en_result_t I2CRet = Error;
- float Vapd = 0.0;
- int16_t DAC_OUT_TEMP = 0;
- int32_t main(void)
- {
- sys_clk_init();
- user_apdgpio_init();
- user_uart_init();
- user_dac_init();
- user_adc_init();
- user_i2c_init();
-
- kx023_1025_config();
- apd_enable();
-
-
- while(Ok != Flash_Init(1, TRUE)){
- ;
- }
-
-
- while(1)
- {
-
- if(FpgaRxQueue.size > 0){
- QueuePop(&FpgaRxQueue, fpgaRx);
- fpgaRxFlag = 1;
- }
-
- if(PcRxQueue.size > 0){
- QueuePop(&PcRxQueue, pcRx);
- pcRxFlag = 1;
- }
-
-
- if(fpgaRxFlag == 1){
- fpga_cmd_ret = execute_fpga_cmd();
- // send_data_to_fpga(fpgaRx, 8);
- fpgaRxFlag = 0;
- }
-
- if(pcRxFlag ==1 ){
- pc_cmd_ret = execute_pc_cmd();
- //send_data_to_pc(pcRx, 8);
- pcRxFlag = 0;
- }
-
-
-
-
- user_apd_output_set(140);
-
- get_apd_adc(); // ▲ 重点是这
-
- get_temperature_adc(); // ▲ 和这
-
-
-
- kx023_1025_read();
-
- send_data_to_pc(angle_data,8);
-
-
- delay1ms(1);
-
-
-
- }
- }
-
-
-
user_adc.c
- #include "user_adc.h"
- #include "gpio.h"
- #include "bgr.h"
- #include "adc.h"
-
- uint8_t ADC_UNIT = ERROR_UNIT;
- uint8_t ADC_FLAG = ADC_WAITING;
-
- uint16_t Trim = 0;
- uint32_t u32AdcRestult0;
- uint32_t u32AdcRestultTemperature;
- float Vapd_sense = 0;
- float temperature = 0;
-
- // ADC端口 配置
- void adc_gpio_config(void)
- {
- Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE); // 开启ADC/BGR GPIO外设时钟
- Gpio_SetAnalogMode(GpioPortA, GpioPin0); // PA00 (AIN0)
- }
-
- // ADC模块 初始化
- void adc_config(void)
- {
- stc_adc_cfg_t stcAdcCfg;
- DDL_ZERO_STRUCT(stcAdcCfg);
-
- // 开启ADC/BGR外设时钟
- Sysctrl_SetPeripheralGate(SysctrlPeripheralAdcBgr, TRUE);
-
- Bgr_BgrEnable(); // 开启BGR
- Bgr_TempSensorEnable(); // 【开启温度传感器】
-
- // ADC 初始化配置
- stcAdcCfg.enAdcMode = AdcSglMode; // 采样模式-单次
- stcAdcCfg.enAdcClkDiv = AdcMskClkDiv8; // 采样分频-1
- stcAdcCfg.enAdcSampCycleSel = AdcMskSampCycle12Clk; // 采样周期数-12
- stcAdcCfg.enAdcRefVolSel = AdcMskRefVolSelInBgr2p5; // 参考电压选择-内部2.5V
- stcAdcCfg.enAdcOpBuf = AdcMskBufEnable; // OP BUF配置-开
- stcAdcCfg.enInRef = AdcMskInRefEnable; // 内部参考电压使能-开 AdcMskInRefDisable AdcMskInRefEnable
- stcAdcCfg.enAdcAlign = AdcAlignRight; // 转换结果对齐方式-右
-
- Adc_Init(&stcAdcCfg);
- }
-
- // ADC 温度单次采样模式 配置
- void get_temperature_adc(void)
- {
- Adc_CfgSglChannel(AdcAiTsInput);
-
- // 启动单次转换采样
- Adc_SGL_Start();
-
- ADC_FLAG = ADC_WAITING;
-
- while(ADC_FLAG == ADC_WAITING){
- if(TRUE == Adc_GetIrqStatus(AdcMskIrqSgl))
- {
- Adc_ClrIrqStatus(AdcMskIrqSgl); ///< 清除中断标志位
- u32AdcRestultTemperature = Adc_GetSglResult();
-
- Trim = *((uint16_t *)(0x00100C36));
- temperature = 25 + 0.2135 * (float)(u32AdcRestultTemperature - Trim );
- ADC_FLAG = ADC_COMPLETED;
-
- // Adc_SGL_Stop(); ///< ADC 单次转换停止
-
- }
- }
- }
-
- // ADC 温度单次采样模式 配置
- void get_apd_adc(void)
- {
-
- Adc_CfgSglChannel(AdcExInputCH0);;
- // 启动单次转换采样
- Adc_SGL_Start();
-
- ADC_FLAG = ADC_WAITING;
- while(ADC_FLAG==ADC_WAITING){
- if(TRUE == Adc_GetIrqStatus(AdcMskIrqSgl))
- {
- Adc_ClrIrqStatus(AdcMskIrqSgl); ///< 清除中断标志位
- u32AdcRestult0 = Adc_GetSglResult();
-
- Vapd_sense = (float)u32AdcRestult0*0.054267632; // 2.5V内部参考电压
- ADC_FLAG = ADC_COMPLETED;
- // Adc_SGL_Stop(); ///< ADC 单次转换停止
- }
- }
- }
-
-
-
- void user_adc_init(void){
- adc_gpio_config();
- adc_config();
- }
-
-
user_adc.h
- #ifndef _USER_ADC_H_
- #define _USER_ADC_H_
-
- #include "ddl.h"
-
- #define ERROR_UNIT 0
- #define TEMPERATURE_UNIT 1
- #define APD_UNIT 2
-
- #define ADC_WAITING 0
- #define ADC_COMPLETED 1
-
- extern float temperature;
- extern float Vapd_sense;
- extern uint8_t ADC_UNIT;
- extern uint8_t ADC_FLAG;
-
- void adc_gpio_config(void);
- void adc_config(void);
-
- void user_adc_init(void);
-
- void get_temperature_adc(void);
- void get_apd_adc(void);
-
- #endif
-
2022-12-05:
华大技术支持今天到我司进行交流, 内部测温的问题解决了,我们不用降主频, 把ADC 8分频之后,等待周期换成12个cycle。在单次采集的时候, 切换通道之后等待10ms或者更少的时间。 温度测量值就是正确的。
- // ADC 温度单次采样模式 配置
- void get_temperature_adc(void)
- {
- Adc_CfgSglChannel(AdcAiTsInput);
- delayms(10); // 这里做个延迟
感谢您的阅读,欢迎留言讨论、收藏、点赞、分享。