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

#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

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

相关文章

学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习...
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面...
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生...
Can’t connect to local MySQL server through socket \'/v...
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 ...
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服...