CMT2380/HC32L110入门踩坑记录

写在前面

本帖子不定期更新,记录本人遇到的问题。CMT230F32的微控单元是基于HC32L110。

1.空白工程启动文件的问题

使用官网空白工程CMT2380F32按照自己需求的工程时,需要注意到启动文件startup_CMT2380F32.s和官网给的example里面的启动文件是不一样的,官方可能后面改了也没注意到。
主要是启动文件中对中断服务函数的定义有差别,导致无法触发任何中断函数。
新启动文件
老启动文件
解决方案是打开dll.h注释掉所有中断服务函数宏定义(因为启动文件定义过了,而后面旧版本的中断服务函数在这个工程里已经没有了)
在这里插入图片描述

2.RTC时钟问题

RTC时钟默认使用外部晶振,但是CMT2380的外部晶振给了射频,需要手动初始化内部RCL,否则RTC读取到的时间不变(初始化也不返回错误)可以考虑这样初始化,使能内部RCL不会影响系统内部时钟。

	Clk_SetRCLFreq(ClkFreq32768);
	Clk_Enable(ClkRCL, TRUE);
	Clk_SetPeripheralGate(ClkPeripheralRtc,TRUE);

3.UART格式化输出的问题

HC32L110使用格式化输出的方法官方有教程。我这里用了微库,但是默认使用uart0作为调试串口,如果使用其他uart需要修改库文件。
解决方案:打开dll.c,修改Debug_Output(uint8_t u8Data),将所有的uart0都换成uart1(或者其他的)

void Debug_Output(uint8_t u8Data)
{
    M0P_UART1->SCON_f.REN = 0;
    M0P_UART1->SBUF = u8Data;

    while (TRUE != M0P_UART1->ISR_f.TI)
    {
        ;
    }
    M0P_UART1->ICR_f.TICLR = 0;
}

4.SysTick进行延时

问题描述:改变RCH频率后官方库的延时函数延时错误
在启动文件里,RCH默认是4MHz,官方库给了2个延迟函数利用SystemCoreClk记录RCH主频,且这个值默认是4MHz。
当我们改变时钟频率后,不会自动更新SystemCoreClk,于是延时错误,如我用16M会比正常时间快四倍。

在这里插入图片描述
解决方法有二个:
1。在你修改过时钟后,加上

SystemCoreClock=Clk_GetHClkFreq();
//或者这个
SystemCoreClockUpdate();

2.将delay1ms函数中的SystemCoreClock替换成Clk_GetHClkFreq()

5.SW调试卡住或运行后卡住

问题描述:函数参数的指针是错的或是空指针,在调试中会卡在某一段代码,但不一定是卡在你函数调用的那一段代码,通常是直接卡在调用函数的代码前。
这个问题对printf也会生效,如

f1();
f2();
printf("%d",a[0]);

假如数组a没有初始化,,那很可能在f1或f2就卡住了。即便已经初始化了,如果之后没有再用到数组a(没有在主循环出现),很可能会卡住,通常会卡在f1或者f2导致无法分析问题出在哪。
除了自己操作失误以外,很有可能是编译器给优化掉了。
建议这样选择,然而实际测下来还不够,要把重要的指针设为全局。
在这里插入图片描述

6.printf和串口接收中断的冲突

当使用微库的printf时,这样接收串口助手发送的一串字符(接收一个字符中断一次,一共中断7次)。假如说在程序的其他地方用了printf以后,会发现只能接收到一个字符串,然后再也无法进入Uart接收中断。
在这里插入图片描述
例如,这样用printf输出接收到的字符串,仅能输出一次,然后经过调试发现,继续向HC32L110输入字符串,再也没有进入中断。其原因不明。

		if(u8RxFlg)
		{
			u8RxFlg = 0;
				i=1;
				printf("%s\n",u8RxData);
				M0P_UART1->ICR_f.RICLR = 0;
				}

但经过测试,发现printf用重定向的方法则不存在这个问题。
在dll.c里面注释掉fputc函数,然后在main里面重写它。详细可以参考这篇https://blog.csdn.net/willOkay/article/details/106819262

int fputc(int ch, FILE *f)
{
Uart_SetTb8(UARTCH1,Even,ch);
	Uart_SendData(UARTCH1,ch);
	return ch;
}

改为重定位的方法后,printf和uart接收中断不再冲突,但是注意不能在接收的过程用printf,比如在中断函数中不要使用printf、在七次中断的中间也尽量不使用。

7.16位低功耗计时器LPT实现更长计时

HC32L110的LPT为16位,向上计数,因此假如说你要定时x毫秒,理论公式是0xFFFF-x32.768,由于不支持浮点数,因此实际寄存器里写理论公式是0xFFFF-x32。由于忽略了小数部分,这样做误差很大。无法用算法补偿的情况下,比如用低功耗计时器从深度休眠状态定时唤醒MCU。可以采用100ms单位的计数方式,即只计数100毫秒的整数倍,其余的时间通过通用计时器实现,计数100ms的方法如下:

void MySetLPT100ms(uint16_t ms100)
{
    //Lpt 中断使能
    Lpt_ClearIntFlag();
    Lpt_EnableIrq();
    EnableNvic(LPTIM_IRQn, 3, TRUE);

    Lpt_ARRSet(0xFFFF-3276*ms100);
    Lpt_Run();

}

void MydisableLPT(void)
{
Lpt_ClearIntFlag();
	EnableNvic(LPTIM_IRQn,3,FALSE);
	Lpt_Stop();
}

void SetSleepOnce(uint16_t Sleeptime)
{
	#ifdef EnableSleep
		MySetLPT100ms(Sleeptime);
		SystemSleep();
		MydisableLPT();
	#endif
}

但是这样做一次计时的上限是19百毫秒,假如说计时时间很长,要超过2秒的话,就不能一次解决。
以计时3秒钟为例,如果这样写,实际计时偶尔会出现错误,多数时候是成功执行了3次100ms计时,偶尔只会成功执行2次计时

SetSleepOnce(10);
SetSleepOnce(10);
SetSleepOnce(10);

猜想是硬件根据寄存器调整需要时间。需要在相邻两次计时间加入延迟,我的定时函数是这样写的,可以实现256*10百毫秒的定时,uint8改了也可以更长:

	uint8_t LPTtimerset(uint8_t tim)
	{
		if(tim>10)
		{
			SetSleepOnce(10);//只睡眠100的整数倍
			delay100us(1);//延迟,避免错误
		return LPTtimerset(tim-10);
		}else
		{
		SetSleepOnce(tim);//只睡眠100的整数倍
		return tim;
		}
	}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值