例子0:https://www.kdocs.cn/l/cp1DT0sq6ltW
例子1:
gsm_info = NULL; //这里给指针赋值0x00000000 gsm_info = (TYPE_GSM_PROCESS *)OSQPend(&gsm_process_q, OSCfg_TickRate_Hz, OS_OPT_PEND_BLOCKING, &size, NULL, &err); if(err == OS_ERR_NONE) { if(gsm_info == NULL) { continue; //进入下一个循环 } sim800c_status_key = gsm_info->sim800c_status_key; } sim800c_main_process(gsm_info);//如果没有新的消息,那么gsm_info就是NULL,但是在函数里也不会调用。 free_gsm_processreq(gsm_info);//程序在这里就硬件错误了,是因为gsm_info是一个空指针,不能对其操作例子2:
void gsmprecheck_task(void *pdata) { OS_ERR err; pdata = pdata; while(1) { OSSemPend(&gsm_precheck_sem, 0, OS_OPT_PEND_BLOCKING, NULL, &err);//这个信号不能正常运行 if(err == OS_ERR_NONE) { sim800c_precheck_rev(); } } }信号量gsm_precheck_sem是在串口接受数据后post的。不能正常接受的原因根本上是优先级的问题,没有安排好,也是因为比它优先级更高的任务里的延时用的delay_ms,没有使用OS里延时API。
在不用OS的程序里,相当于单线程,任务与任务之间只能只用标志位交流,但是如果使用OS,是多线程使用,任务之间的交流需要更加紧密、次序分明,所以需要使用信号量,如果离的比较远,要求不高可以使用标志位。
例子3:
在UCOSIII中遇到了程序死机,不再运行,也不会进HardFault中断,但调试时明显的就是延时不正常,一般可能就是某个任务的栈空间不够。
例子4:
u8 sim800c_send_cmd(u8 *cmd, u8 *ack, u16 waittime) { u8 times; u8 res = 0; if(cmd != NULL) { sim800c_send_TTL(cmd, strlen((char *)cmd));//指令都是字符串 } waittime = waittime*100; sim800c_rx_complete = 0; for(times = 0; times < waittime; times++)//由于变量times是一个字节,不能大于255,所以输入值为3,则出问题 { delay_ms(1000/100); if(1 == sim800c_rx_complete) { if(sim800c_check_cmd(ack)) { break;//得到有效数据 } else { res = 1;//没有得到有效数据 } } } return res; }给一个字节变量赋值大于255的数,是经常被疏忽的问题,值得警惕。
例子5:
例子6:
电表休眠后由超级电容供电,当出现供电电流变化震荡时,可能是超级电容没充满。HT6333在休眠后可以每500ms进行一次温度采样,导致供电电流在4~20uA内震荡。
例子7:
FM33LC0单片机串口用8N1,上位机用8E1或者8O1通信,大部分报文通信失败,偶尔成功。改单片机串口用8N2,上位机通信都成功。排查次问题测试了两个USB-TTL模块互相发,发现校验位+停止位大于等于2个bit,通信都能成功。应该是模块问题,不判断校验位了。
例子7:
头文件异常问题:
- 不加#ifndef #define,导致无限包含,浪费编译资源;
- 加#ifndef #define,不同头文件交叉引用,可能导致某些类型未定义(见错误集20250612);
- 头文件中定义变量,多个C文件包含该头文件,重定义编译报错;
- 头文件中定义的变量加static,浪费空间,若多个不同头文件定义同名变量,且被一个C文件引用,编译报错;
注意:头文件引用包括头文件路径是不判断大小写的
例子8:
SPI全双工,是因为它的总线设计,但在单片机应用中,分主机从机,一问一答,信息是以半双工的方式传递的。https://www.kdocs.cn/l/cmwq2PdW4jxf
UART全双工,发送和接收都是独立进行的。
CAN和485是差分线,只能是半双工。
100K速率的EE,用页写的话大概10字节1ms,不算结束等待时间。
例子9:
在写驱动时,对于异常情况的处理,如果检查开销小,就先检查,反之则先运行,在超时等错误发生后再处理。软件iic可以提前判断sda口线电平,硬件iic可以提前判断busy位,如果单片机不支持busy,则通过口线配置先当成软件iic处理,再设置复用功能。
如果是特别重要的器件,最好先检查,等运行错误后再处理可能就来不及了。
例子10:
参数保固其实是参数和数据保固,需要频繁会对外产生交互都可以放在里面。变量保固主要是自己产生并需要频繁使用的。
不能在中断中使用参数保固读接口,由于参数保固会定期破坏CRC,导致在中断中读EE。关于参数保固使用场景总结:
1、单个参数配单个CRC,长度较小,且无需在中断中使用。
建议使用:参数保固服务。
2、多个参数配单个CRC或者参数较大,或者在中断中使用。
建议使用:
用参数保固的思想,将原本服务里的接口代码展开处理。除了定期检查CRC(也有用的时候才检查),也要定期破坏CRC(一般是15分钟),刷新RAM的参数。
修改参数的时候,先改RAM参数,然后再写EE。后续可以破坏CRC,也可以不破坏,可以立马检查CRC也可以等定期。
刷新参数的时候,先从EE读到临时变量,和参数比较后再复制到参数上,如果参数需要在中断中使用,这个复制过程就需要原子操作。
3、某些组件由于高内聚需求,即使满足第1点使用情况,也不用参数保固服务,参数需要自我管理,用法上同第2点。
4、串口波特率之类的硬件参数最好通过判断变化,及时重置硬件,可以不用消息机制。
例子11:
int a = b = c = 4; //编译报错,b和c未定义 int a, b, c; a = b = c = 4; //ok if (a == b = c) //编译报错,==的优先级比=高 { } if (a == (b = c)) //ok { }例子12:
单片机在调试中打断点,暂停的是CPU的运行,各外设继续运行。
20251202
进休眠前,一定要先关闭所有可能唤醒休眠的外设,然后再设置唤醒源。比如RTC中断,即使已经禁用全局中断也无用。
HT5023单片机在进sleep模式前要使能全局中断,否则不会进休眠,原因未知。
20251208
钜泉单片机的IO有推挽和上拉,对于普通输出或者数字输出,上拉功能无效;对于普通输入和数字输入,推挽功能无效;对于模拟功能和LCD功能,推挽和上拉都无效。
20251216
正常开发中使用EE存参数和关键数据,如果使用flash存参数和关键数据,即使用easyflash等的软件组件,有磨损均衡、原子操作、坏块管理等,但是无法解决在掉电保存时可能触发擦扇区这一动作。EE存一页固定耗时5ms,但flash擦一页典型30ms,最大400ms,无法接受。
easyflash可以作为消费级产品上的参数管理,但是在工业级别上是不能用的,关键数据的及时且100%的保存是必须的。如果使用场景中可以接受掉电时参数回滚,就可以用easyflash或者littlefs。
easyflash可以认为是一个简化版的文件系统,如果用来存参数,比较适合参数量少的情况,一旦数量上去,读写会很慢,也不能接受。基本上如果是电表类应用(单片机主频很低),一般都是直接操作硬件,提高响应速度,根据实际需求走。
如果在电表上不得已只能用flash替代EE,需要确保掉电保存时不用擦扇区。1、平时修改参数时,使用实时刷写,不用走缓存;2、上电时准备好掉电保存的扇区,掉电时直接写。这样一来就需要重新设计一套方案,不能用easyflash,可以借鉴它的优秀思想,但还是挺麻烦的。。。没有必要搞这一套。同时自己需要对网上那套“库”去魅。
20251224
节拍(不一定指节拍服务)更加适用于周期性功能要求,或者某种时序实现。延时服务则更多的适用于某些超时或者延续多长时间的概念。虽然某种程度上两者可以互相实现对方的功能,但是我们使用的时候尽量贴合它的本意。
20260202
在实际单片机开发中,在环形队列上,队列元素最好是2的幂次数,这样取模运算(40个时钟周期)可以用位与替代,更加适合在中断通信上。通信环服务是从kfifo的基础上改进而来,但回绕点是SIZE+1,且不判断队满,可以不断的塞数据。信号环一般不会频繁调用,近似最小实现,但是多了一个整倍数回绕点,不浪费一个存储空间。现有算法服务虽然不是标准的易理解的,但是足够使用,并具有较大共识,所以我只需要了解它怎么实现,并知道标准实现即可,不强求、多包容。
20260205
优化等级对软件延时的影响最大!
/* ******************************************************************************** * 函 数 名: i2c_Delay * 功能说明: I2C总线位延迟,最快400KHz,不能被优化 * 形 参: 无 * 返 回 值: 无 ******************************************************************************** */ #pragma optimize = none static void i2c_Delay(uint8_t index) { switch (index) { case SOFT_I2C1_INDEX: for (int i = 0; i < 3; i++); break; default: break; } }20260416
矩泉单片机上的串口标志只有接收完成和发送完成。串口的驱动代码在移植到GD上时,接收完成用接收非空标志替代,发送完成用发送空标志替代,会出问题。
原因:矩泉上是先使能发送完成中断,然后发送一个字节触发中断,在GD上是使能发送空中断后立马就会触发中断,导致异常。
补充:单片机上发送空标志置位后,数据还要等一会儿才能从引脚发送完毕,只有发送完成标志置位后,串口引脚才算真正把数据发完。
20260708
问题现象:HT6025K的休眠功耗高,或者测量RTC电池功耗跳变快。
原因:芯片休眠后,即使没有VCC,只有VRTC供电,也会根据TMPPRD的值,周期采样温度补偿RTC。在没有VCC的情况下,VRTC断开又连上,也算冷启动,温度0.5s采样一次。
20260709
CMOS器件的Latch-Up(闩锁效应)特性,EMC实验时,容易有电流进入导致闩锁。浮空输入和无上拉开漏输出高模式容易受影响。
norflash的口线容易被打坏,无法读写,需要重新掉上电。