华大HC32L110全是坑
有个低功耗项目,本来想用新塘新品ML51,为了支持国产,看到华大HC32L110也可以,画了块板,谁知这个货一步一个坑,手册写的也不严谨,历程不全且不细致,现在问题ADC单次采集外部通道一切正常,但采集内部温度传感器和1/3VCC就是不行,有关这2路也已经按照手册进行了设置,另外若完全按手册ADC设置流程配置保准都不行,白白浪费我好多天时间,再不行只能放弃。函数库写的很复杂,一个小小的单片机搞这么复杂干嘛,想不用函数库或用部分函数,部分这届寄存器,但发现好多具体问题,连个中断函数都搞成回调,改了吧又怕和官方不兼容。 请留下联系方式,会有FAE跟进解决。
根据据你的描述,可能是没有打开ADC内的BUFEN.
-----------------------------
寄存器中关于采样1/3VCC及温度传器器的说明如下。
0101:选择通道5输入P3.5
0110:选择通道6输入P3.6
0111:选择通道7输入P0.1
1000:选择通道8输入P0.2
1001:1/3VCC 注:ADC_CR0.BUFEN必须为1
1010:内置温度传感器输出电压 注:ADC_CR0.BUFEN必须为1
1011:内部基准1.2V输出电压 注:ADC_CR0.BUFEN必须为1 开启buff之后,也有注意采用速率,ADC_Clk /(采样时间(4~12clk)+转换时间16个clk),不得超过200K。 smartpower 发表于 2019-5-26 14:24
根据据你的描述,可能是没有打开ADC内的BUFEN.
-----------------------------
寄存器中关于采样1/3VCC及温 ...
开了 Q80351951 发表于 2019-5-26 14:46
开了
能否把你的代码贴上来看看? 本帖最后由 Q80351951 于 2019-5-26 15:14 编辑
martinhu 发表于 2019-5-26 14:59
能否把你的代码贴上来看看?
uint32_t init_adc(void)
{
/*
DDL_ZERO_STRUCT(stcAdcCfg);
DDL_ZERO_STRUCT(stcAdcContCfg);
DDL_ZERO_STRUCT(stcAdcIrq);
DDL_ZERO_STRUCT(stcAdcIrqCalbaks);
//ADC配置
Adc_Enable();
M0P_BGR->CR_f.BGR_EN = 0x1u;//BGR必须使能
M0P_BGR->CR_f.TS_EN = 0x1u; //内置温度传感器,视使用需求
delay100us(1);
stcAdcCfg.bAdcInBufEn = 1;
stcAdcCfg.enAdcOpMode = AdcNormalMode; //连续采样模式
stcAdcCfg.enAdcClkSel = AdcClkSysTDiv2; //PCLK
stcAdcCfg.enAdcSampTimeSel = AdcSampTime4Clk; //8个采样时钟
stcAdcCfg.enAdcRefVolSel = RefVolSelInBgr2p5; //参考电压:内部2.5V(avdd>3V,SPS<=200kHz)
//stcAdcCfg.enAdcRefVolSel = RefVolSelAVDD; //参考电压:AVDD
stcAdcCfg.bAdcInBufEn = TRUE;
//stcAdcCfg.bAdcInBufEn = FALSE; //电压跟随器如果使能,SPS采样速率 <=200K
stcAdcCfg.enAdcTrig0Sel = AdcTrigDisable; //ADC转换自动触发设置
stcAdcCfg.enAdcTrig1Sel = AdcTrigDisable;
Adc_Init(&stcAdcCfg);
stcAdcIrq.bAdcIrq = TRUE; //转换完成中断函数入口配置使能
stcAdcIrq.bAdcRegCmp = FALSE;
stcAdcIrq.bAdcHhtCmp = FALSE;
stcAdcIrq.bAdcLltCmp = FALSE;
stcAdcIrqCalbaks.pfnAdcContIrq = AdcContIrqCallback; //转换完成中断入口函数
Adc_ConfigIrq(&stcAdcIrq, &stcAdcIrqCalbaks); //转换中断入口函数配置
Adc_EnableIrq(); //中断使能
Adc_CmpCfg(&stcAdcIrq); //结果比较中断使能/禁止配置
stcAdcContCfg.enAdcContModeCh = AdcExInputCH4; //通道0 P24
// stcAdcContCfg.enAdcContModeCh = ADCIN_VCC; //通道0 P24
stcAdcContCfg.u8AdcSampCnt = 0x00u; //P24 连续累加次数(次数 = 0x09+1)
stcAdcContCfg.bAdcResultAccEn = FALSE; //累加使能
Adc_ConfigContMode(&stcAdcCfg, &stcAdcContCfg);
*/
M0P_ADC->CR0_f.ADCEN = 1u;
M0P_BGR->CR_f.BGR_EN = 0x1u;//BGR必须使能
M0P_BGR->CR_f.TS_EN = 0x1u; //内置温度传感器,视使用需求
delay100us(1);
M0P_ADC->CR0_f.SEL = ADCIN_temp;
M0P_ADC->CR0_f.ADCEN = 1u;
M0P_ADC->CR0_f.CLKSEL = AdcClkSysTDiv2;//pstcAdcConfig->enAdcClkSel;
M0P_ADC->CR0_f.SAM = AdcSampTime4Clk;//pstcAdcConfig->enAdcSampTimeSel;
M0P_ADC->CR0_f.SREF = RefVolSelInBgr2p5;//pstcAdcConfig->enAdcRefVolSel;
M0P_ADC->CR1_f.CT = 0u;
M0P_ADC->CR0_f.BUFEN = TRUE;//pstcAdcConfig->bAdcInBufEn;
M0P_ADC->CR0_f.IE = 1u;
M0P_ADC->CR1_f.REGCMP = 0u;
M0P_ADC->CR1_f.HTCMP = 0u;
M0P_ADC->CR1_f.LTCMP = 0u;
M0P_ADC->CR1_f.RACC_EN = 0u;
M0P_ADC->CR1_f.TRIGS0 = 0u;
M0P_ADC->CR1_f.TRIGS1 = 0u;
M0P_ADC->CR2_f.ADCCNT = 0u;
M0P_ADC->CR2_f.CH0EN = 0u;
M0P_ADC->CR2_f.CH1EN = 0u;
M0P_ADC->CR2_f.CH2EN= 0u;
M0P_ADC->CR2_f.CH3EN= 0u;
M0P_ADC->CR2_f.CH4EN= 0u;
M0P_ADC->CR2_f.CH5EN= 0u;
M0P_ADC->CR2_f.CH6EN= 0u;
M0P_ADC->CR2_f.CH7EN= 0u;
EnableNvic(ADC_IRQn, 3, TRUE);
return Ok;
}
void ADC_IRQHandler(void)
{
M0P_ADC->ICLR_f.CONT_INTC = 0u;
adc_count++;
AD.ch++;
switch (AD.ch)
{
case 1:
M0P_ADC->CR0_f.SEL = ADCIN_300v;
AD.temp += M0P_ADC->RESULT_f.RESULT;//取温度AD数据
M0P_ADC->CR0_f.START = 1u;
break;
case 2:
M0P_ADC->CR0_f.SEL = ADCIN_bright;
AD.R3 += M0P_ADC->RESULT_f.RESULT;//取电阻AD数据
M0P_ADC->CR0_f.START = 1u;
break;
case 3:
M0P_ADC->CR0_f.SEL = ADCIN_batt;
AD.bright += M0P_ADC->RESULT_f.RESULT; //取光敏AD数据
M0P_ADC->CR0_f.START = 1u;
break;
case 4:
M0P_ADC->CR0_f.SEL = ADCIN_temp;
AD.batt += M0P_ADC->RESULT_f.RESULT; //取光敏AD数据
break;
}
}
SCS_SETENA 01008040
SCS_IPR0 00000000
SCS_IPR1 00C00000
SCS_IPR2 00000000
SCS_IPR3 C0000000
SCS_IPR4 00000000
SCS_IPR5 00000000
SCS_IPR6 000000C0
SCS_IPR7 00000000
ADC_CR0 4565
ADC_CR1 0000
ADC_CR2 0000
ADC_IFR 0000
ADC_ICLR 000F
Q80351951 发表于 2019-5-26 15:02
uint32_t init_adc(void)
{
/*
你这样配置,ADC中断是有问题的,因为单次转换原本是靠查询,不会产生中断的,手册的步骤也只写了查询。
如果想要使用中断功能,可以借助区间比较的中断功能 martinhu 发表于 2019-5-26 15:39
你这样配置,ADC中断是有问题的,因为单次转换原本是靠查询,不会产生中断的,手册的步骤也只写了查询。
...
你意思是, ADC单次转换不能中断?这不就成半残废了?奇葩。 本帖最后由 martinhu 于 2019-5-27 09:36 编辑
你没看明白我的意思,我是说,可以通过区间比较中断的方式用中断处理。因为这里面就是两个中断,一个是连续转换的中断,一个是区间比较的中断,你不能用单次转换来使用连续转换的中断吧?
看你的代码是用寄存器写的,我刚刚也写了一下,分别是用单次采样的查询和中断两种方式采样1/3Vcc和内部温度传感器,
请参考:
这个是查询方式(main.c文件)
int32_t main(void)
{
M0P_CLOCK->PERI_CLKEN_f.ADC = 1;
M0P_CLOCK->PERI_CLKEN_f.GPIO = 1;
M0P_ADC->CR0_f.ADCEN = 1u;
M0P_BGR->CR_f.BGR_EN = 0x1u;//BGR enable
M0P_BGR->CR_f.TS_EN = 0x1u;
delay100us(1);
M0P_ADC->CR1_f.CT = 0;
M0P_ADC->CR0_f.SREF = 1; //2.5V
M0P_ADC->CR0_f.CLKSEL = 0;//0:PCLK,
M0P_ADC->CR0_f.SAM = 3; //3:12 clk,
M0P_ADC->CR0_f.BUFEN = 1;
/*
When System clk is 4MHz, ADC SPS= 4MHz / (12+ 16) = 143K.
If the BUFEN is set as enable, the ADC SPS must be set less than 200K
*/
while (1)
{
M0P_ADC->CR0_f.SEL = 9;//1/3Vcc
M0P_ADC->CR0_f.START = 1;
while(1 == M0P_ADC->CR0_f.START);
u16AdcVal01 = M0P_ADC->RESULT_f.RESULT;
M0P_ADC->CR0_f.SEL = 10;//temprature
M0P_ADC->CR0_f.START = 1;
while(1 == M0P_ADC->CR0_f.START);
u16AdcVal02 = M0P_ADC->RESULT_f.RESULT;
}
}
这个是中断方式:
(main.c文件)
void Adc_Int(void)
{
if(1 == M0P_ADC->IFR_f.HHT_INTF)
{
if(9 == u8FlagChannel)
{
u16AdcVal01 = M0P_ADC->RESULT_f.RESULT;
}
else if( 10 == u8FlagChannel)
{
u16AdcVal02 = M0P_ADC->RESULT_f.RESULT;
}
else
{
}
M0P_ADC->ICLR_f.HHT_INTC = 0;
}
}
int32_t main(void)
{
M0P_CLOCK->PERI_CLKEN_f.ADC = 1;
M0P_CLOCK->PERI_CLKEN_f.GPIO = 1;
M0P_ADC->CR0_f.ADCEN = 1u;
M0P_BGR->CR_f.BGR_EN = 0x1u;//BGR enable
M0P_BGR->CR_f.TS_EN = 0x1u;
delay100us(1);
M0P_ADC->CR1_f.CT = 0;
M0P_ADC->CR0_f.SREF = 1; //2.5V
M0P_ADC->CR0_f.CLKSEL = 0;//0:PCLK,
M0P_ADC->CR0_f.SAM = 3; //3:12 clk,
M0P_ADC->CR0_f.BUFEN = 1;
/*
When System clk is 4MHz, ADC SPS= 4MHz / (12+ 16) = 143K.
If the BUFEN is set as enable, the ADC SPS must be set less than 200K
*/
M0P_ADC->HT_f.HT = 0;
//M0P_ADC->LT_f.LT = 0;
//M0P_ADC->CR1_f.REGCMP = 1;
M0P_ADC->CR1_f.HTCMP = 1;
//M0P_ADC->CR1_f.LTCMP = 1;
M0P_ADC->CR0_f.IE = 1;
EnableNvic(ADC_IRQn,3,TRUE);
while (1)
{
M0P_ADC->CR0_f.SEL = 9;//1/3Vcc
u8FlagChannel = 9;
M0P_ADC->CR0_f.START = 1;
delay100us(1);
M0P_ADC->CR0_f.SEL = 10;//temprature
u8FlagChannel = 10;
M0P_ADC->CR0_f.START = 1;
delay100us(1);
}
}
(interrupts_hc32l110.c文件):
void ADC_IRQHandler(void)
{
//Adc_IRQHandler(0);
Adc_Int();
}
(interrupts_hc32l110.h文件):
extern void Adc_Int(void);
全身坑啊全是坑 有个项目刚用了110,低功耗非常好,1000uf电容工作15分钟没问题,但没用AD,效果还不错,有问题找FAE基本都能解决,目前用了这么多单 片机,华大的FAE还是很不错的,希望工程师们大力支持,都用国内芯片。 台湾新唐也算国产货吧? 用国产芯片千万别用库,千万别用库,宁愿自己多折腾一下程序,也别用他们的库。看数据手册是考验你语文功底了,并且一定要看最新的数据手册!不然可能你调试一直有问题的某功能在最新的数据手册里该已经被删除了。我不是国产黑,以上只是我使用几款国产芯片之后的真实体验和衷心提醒。这是现阶段国产芯片普遍存在的问题,希望今后越来越好! 应该不是坑 为了开发方便而已 我觉得每个厂家的都是这样啊没啥坑不坑的说法吧 只能说明楼主代码读的还比较少 以前我刚接触st的时候 也有这种感觉 不过看多了 也就习惯了 楼主也慢慢适应吧 martinhu 发表于 2019-5-26 16:26
你没看明白我的意思,我是说,可以通过区间比较中断的方式用中断处理。因为这里面就是两个中断,一个是连续 ...
多谢已经搞定了,问题出在不知道AD单次竟然不会中断,表示这个设计很奇葩,之前能用原因是我自己都没注意是开着连续转换,好在还有变通的方法,昨天就已经搞定了。 本帖最后由 Q80351951 于 2019-5-27 13:04 编辑
本来就使用的一个新的芯片有些寄存器不了解,用库也是顺藤摸瓜,但库搞的太复杂那这根藤就有点太长了,不出问题很快,出了问题还得一点一点查找反而浪费时间,库可以有,也应该有,也很有用但不要搞那么复杂,太复杂没意义,毕竟有时还会遇到空间不够的时候,当你用一款芯片用久了,就不再用库了,节省资源。用过几款带库的,我基本上就是越用调用库函数越少。