STM32部分:
1、问题:在调试公司项目的时候,将使用DMA2的5通道采集adc3的子工程代码移植到总工程代码中,发现程序在进入到主循环的时候总是卡死。
寻找问题:使用mdk DEBUG仿真,停止仿真程序会停在HardFault_Handler函数里的死循环while(1)中。这说明STM32出现了硬件错误。最后发现总工程中也用到了 DMA2的通道5,是用在uart4_TX上的,在硬件资源分配上产生了冲突,最后导致程序卡死。
解决办法:使用ADC3多通道采集的非DMA方式,让出DMA资源。
2、问题:使用MDK写程序并编译出现
..\Vehicle\pedal.c(166): error: #18: expected an expression
寻找问题:最后在网络上找到了问题所在
Misc Controls 在MDK中默认是C90,将其改为C99即可解决
解决办法:如下图所示添加--c99
3、问题:定义结构体导致出现内存大小异常问题
4、问题:在调试别人的程序过程中发现程序卡死。
寻找问题:经过仿真发现程序总是在启动文件的
DMA2_Channel2_IRQHandler
DMA2_Channel3_IRQHandler
DMA2_Channel4_5_IRQHandler
B .
ENDP
ALIGN 这里卡死,一直卡在B那里,返回不了。
解决办法:与往常一样在网上寻找解决方案。最后了解到如果初始化了一个定时器但是却没有定义它的中断函数,导致找不到中断入口就死了,就会出现此类错误。
5、问题:写好代码,并在stm32上烧录,发现程序中的timer5,始终无法进入中断运行。
寻找问题:经过分析,我的代码配置的芯片是是符合调试的芯片的,都是stm32f103t8u6,但是我的启动文件和,如下图所示define处定义的是 STM32F10X_HD,当将HD换成MD后此时已经找不到timer5的中断相关配置的宏,说明此芯片属于小型号的stm32系列的产品,不含有timer5。
解决办法:将timer5换成timer3等其他的t8系列含有的定时器。
6、问题:说一个由于自己粗心大意而产生的问题,导致自己浪费了半个小时的时间
一个结构体变量sendata在一个Laser_ranging.c文件中使用,明明添加了相关DATASend.h文件,DATASend.h文件中也声明了该变量,但是提示error: use of undeclared identifier
找到问题:最后在DATASend.h(如下代码所示)中发现 __RS485_H在另一个.h文件中已经用过了,又恰好在Laser_ranging.c文件中两个.h都包含了,所以只能包含一个,恰好排除了后一个DATASend.h的包含。
#ifndef __RS485_H
#define __RS485_H
#include "stm32f10x.h"
#include <string.h>
#include "Laser_ranging.h"
#define Angle_Data_SIZE_MAX 2U
#define Attitude_Data_SIZE_MAX 9U
typedef struct
{
uint8_t Angle_id0;
uint8_t Angle_id1;
uint16_t Angle_data_length;
uint16_t Angle_data[Angle_Data_SIZE_MAX];
uint8_t Attitude_id0;
uint8_t Attitude_id1;
uint16_t Attitude_data_length;
uint16_t Attitude_data[Attitude_Data_SIZE_MAX];
uint16_t pack_crc;
} Data_TX_Send;
extern Data_TX_Send sendata;
extern void Sensordata_TX_Str_Send(void);
#endif
7、问题:在使用MDK debug调试打开watch窗口,输入变量名,查看变量,对于数组,可以直接出入数组名,就可以查看所有的元素的变量。(之前都是数组元素一个一个的输入,没有想过去尝试,有时导致工作的效率比较低。)
8、问题:在使用MDK 查看公司的老项目的STM32的工程文件,将产品开箱,利用SWD的方式将程序下载到产品中,发现并不会出现该有的现象,后来发现在如下图所示的位置中,可以选择为不同的工程,之前下载的工程为SynboxMini,而应该下载的工程为Synbox。
当程序更改为工程Synbox,就好使了(在此之前并没有用过mdk的这种使用方式)。
9、问题:NMI_Hander中断发生的原因。
待解决:
nrf52832部分
1、问题:在调试公司项目的时候,一块刚刚焊接好的nrf52832蓝牙小板子,板子上有ads1292芯片、mpu9250芯片、stm32f103芯片,ads1292芯片用于采集皮电,mpu9250用于采集三轴加速度数据以排除运动干扰,stm32与52832串口连接传输温度数据。同样的两块小板子 ,一块好使另一块不好使,不好使的现象是,小板子作为Server向Client广播,连接上后(可以连接),发现Server不能向Client发送数据。而另外一块板子好使。
寻找问题:此时,通过排除法可知:(1)另外一块板子好使说明程序并没有问题;(2)小板子既然能够连接Client说明nrf52832没有问题;(3)屏蔽掉stm32的串口发送部分,排除掉串口数据的干扰;(4)然后在代码中屏蔽掉ads1292芯片相关驱动和应用代码,发现小板子依然不好使,排除ads1292的干扰;(5)最后在代码中屏蔽掉mpu9250的相关驱动和应用代码,发现小板子好使了,问题就在MPU9250上。
解决办法:更换MPU9250芯片。
LINUX与C部分
1、Ubuntu下的串口助手cutecom的安装与使用 ,可以体验到在WIN中使用串口助手的感觉。
2、cp210x串口驱动在LINUX环境中的安装与使用
3、ubuntu中的常用命令
4、在ubuntu中开发ESP32环境配置 参考链接:
https://docs.espressif.com/projects/esp-idf/zh_CN/latest/index.html
5、区别yum与apt-up 的区别。
6、在ESP32蓝牙perpher.C文件中 ,结构体赋值操作方式中,对于只带 . 如何来了解 如下,赋值时可按照条件省略相应的结构体明,直接操作其成员进行赋值。
typedef void (* esp_gattc_cb_t)(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param);
typedef struct{
esp_gattc_cb_t gattc_cb;
uint16_t gattc_if;
uint16_t app_id;
uint16_t conn_id;
uint16_t service_start_handle;
uint16_t service_end_handle;
uint16_t char_handle;
esp_bd_addr_t remote_bda;
}gattc_profile_inst;
/* One gatt-based profile one app_id and one gattc_if, this array will store the gattc_if returned by ESP_GATTS_REG_EVT */
gattc_profile_inst gl_profile_tab[PROFILE_NUM] = {
[PROFILE_APP_ID_FOOT] = {
.gattc_cb = foot_gatt_profile_event_handler,
.gattc_if = ESP_GATT_IF_NONE,
.app_id = PROFILE_APP_ID_FOOT,
},
[PROFILE_APP_ID_CHEST] = {
.gattc_cb = chest_gatt_profile_event_handler,
.gattc_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */
.app_id = PROFILE_APP_ID_CHEST,
},
[PROFILE_APP_ID_WRIST] = {
.gattc_cb = wrist_gatt_profile_event_handler ,
.gattc_if = ESP_GATT_IF_NONE,
.app_id = PROFILE_APP_ID_WRIST,
},
[PROFILE_APP_ID_NULL] = {
.gattc_cb = imu_gatt_profile_event_handler,
.gattc_if = ESP_GATT_IF_NONE,
.app_id = PROFILE_APP_ID_NULL,
},
};
此种赋值方式可以与以下这种赋值方式进行对比
typedef struct
{
uint8_t SensorID_Index; //id index
uint8_t SensorID; //high 2bit is sensor number
uint8_t SensorGPSSateliteCount; //sensor battery mesage
uint8_t SensorConnectStatus; //sensor connect status;true or false
#pragma anon_unions
union
{
uint16_t SensorData[SENSOR_DATA_SIZE_MAX]; //sensor data
VEHICLE_DATA_t Vehicle_send;
GPS_DATA_t Gps_Data;
IMU_DATA_t IMU_Data;
};
void (*pSensor_Init_Fun)(void);
void (*pSensor_GetData_Fun)(void);
void (*pSensor_Start_Fun)(void);
void (*pSensor_Stop_Fun)(void);
uint8_t Sensor_Data_RDY;//1:ok,0 not ok
uint8_t DMA_Rx_Status:4;// 0:error,1:half,2:complate
uint8_t DMA_Tx_Status:4;// 0:error,1:half,2:complate
}SENSOR_STRUCT;
SENSOR_STRUCT Sensor_Struct[SENSOR_INDEX_MAX]=
{
{SENSOR_VEHICLE_INDEX, vehicleSensorType, 0, 0, {0,0,0,0,0,0,0,0,0}, Init_Vehicle, Get_VehicleData, StartSample_Vehicle, StopSample_Vehicle}, //
{SENSOR_GPS_INDEX, gpsType, 0, 0, {0,0,0,0,0,0,0,0,0}, Init_Gps, Get_JY901GpsData, StartSample_Gps, StopSample_Gps}, //
{SENSOR_IMU_INDEX, imuType, 0, 0, {0,0,0,0,0,0,0,0,0}, Init_IMU, Get_IMUData , StartSample_IMU, StopSample_IMU}, //
{SENSOR_BACK_INDEX, backSensor, 0, 0, {0,0,0,0,0,0,0,0,0}, Init_Back, Get_BackData, StartSample_Back, StopSample_Back},//
{SENSOR_OBD_INDEX, obdType, 0, 0, {0,0,0,0,0,0,0,0,0}, Init_OBD, Get_OBDData, StartSample_OBD, StopSample_OBD}, //
};
8、关于位段的理解。
六月三日,这是个美好的晴天的日子,在今天阅读代码的时候,又遇到了自己懵逼的地方,如下:
uint8_t DMA_Rx_Status:4; // 0:error,1:half,2:complate
uint8_t DMA_Tx_Status:4; // 0:error,1:half,2:complate
为何定义了一个uint8_t之後,后面会出现一个冒号 : ,经过查找了解到,这是个位段,每个变量占据4个位,使两个变量变为一个字节大小。
9、关于位移<< 、>> 和乘除 * 、/ 之间运算速度的比较的思考:
经过查找资料得到以下结论:
速度:移位>乘法>除法。
计算机中有专门的移位功能部件,这也是最基础的部件。乘法和除法都是靠移位实现的。乘2^n,左移n位,除2^n,右移n位。
另外,原始的乘法器是一步一步乘(移位)出来的,每次取乘数的一位与被乘数操作,1则把被乘数照写,0则为0,然后乘数右移。这样循环,最后把每一步结果加起来。
后面通过阵列连乘器改进速度,一次算出上面每一步的结果,然后直接相加。
乘法是加操作,而除法是每步的结果作加法或减法(加减交替法),有的算法还需要恢复上一次的结果(余数恢复法),而且每一步加减后还要进行移位,所以最慢。
具体参见<<计算机组成原理>>。
因为移位速度快,所以经常被应用。比如给程序加花指令(增加Cracker破解难度)时,很多地方使用移位操作。
10、探讨了关于嵌入式开发中,字节左移合并的问题
比如buff[1] 与buff[2] 要合并为一个字 temp 通常的做法是
temp = buff[1] << 8 + buff[2] ;
但是这种做法会出错,至于为什么会出做........
所以正确的做法为 temp = ( ( ( buff[1] << 8 ) & 0xff00 ) | ( buff[2] & 0x00ff ) );
11、c语言中,符号#与符号##的相关用法。
使用#把宏参数变为一个字符串,用##把两个宏参数贴合在一起.
连接 https://blog.csdn.net/baidu_33850454/article/details/79363033 中有详细说明。
12、不要质疑sizeof宏的运行效率,它在程序编译的时候就已经被计算好了,不参与到程序的实际运行。
警告语错误收集
1、warning: #550-D: variable "d" was set but never used
描述:变量'd'定义但从未使用,或者是,虽然这个变量你使用了,但编译器认为变量d所在的语句没有意义,编译器把它优化了.
解决方法:仔细衡量所定义的变量d是否有用,若是认定变量d所在语句有意义,那么尝试用volatile关键字修饰变量d,若是真的没有用,那么删除掉以释放可能的内存.
2、warning: #1-D: last line of file ends without a newline
描述:文件最后一行不是新的一行.编译器要求程序文件的最后一行必须是空行,想了半天没想通为什么要这样.
解决方法:可以不理会.若是觉得出现警告不爽,那么在出现警告的文件的最后一行敲个回车,空出一行.
3、warning: #111-D: statement is unreachable
描述:声明不可能到达.多出现在这种场合:
int main(void)
{
...
while(1) //无限循环,这在不使用操作系统的程序中最常见
{
...
}
return 0; //这句声明在正常情况下不可能执行到,编译器发出警告
}
解决方法:不理会.
4、 warning: C3017W: data may be used before being set
描述:变量'data'在使用前没有明确的赋值.如:
uint8 i,data; //定义变量i和data,二者都没有明确赋值
for ( i = 0; i < 8; i++) //变量'i'在语句中被赋值0
{
if ( IO1PIN & SO_CC2420 )
data |= 0x01; //变量'data'在使用前没有明确赋值,编译器发出警告
else
data &= ~0x01;
}
解决方法:应仔细衡量该变量的初始值是否为0,若是,可以不理会这个警告,因为MDK编译器在程序执行前,会将使用到的数据区初始化为0,但若是该变量的初始值不应该是0,忽略这个警告可能会引起致命错误.这个警告应引起足够重视.应养成变量赋初值的习惯,好在有编译器给把关.
5、warning: #177-D: variable "temp" was declared but never referenced
描述:变量'temp'进行了声明但没有引用.多出现在声明了一个变量,但却没有使用它,它和warning: #550-D: variable "temp" was set but never used不同之处在于temp从没有使用过.
解决方法:若是定义的变量确实没有用,删除掉;若是有用,则在程序中使用.
与该警告类似的还有 warning: #177-D: function "MACProcessBeacon" was declared but never referenced
6、warning: #940-D: missing return statement at end of non-void function "DealwithInspect2"
描述:返回非空的函数"DealwithInspect2"的最后缺少返回值声明.如:
int DealwithInspect2(uint32 test)
{
...
...
...
//此处应该是return x;返回一个int型数据,若是没有返回值,编译器产生警告
}
7、warning: #1295-D: Deprecated declaration lcd_init - give arg types
描述:在定义函数的时候,如果你写上函数参数,就会有这个警告,比如void timer_init(); 这里就没有形参,如果这样的话,编译器会给出警告.
8、 error: #65: expected a ";"
描述:缺少分号.大多是漏忘';'.
解决方法:双击错误行,在定位到错误点的附近找到没加';'号的语句,加上分号.并不一定在定位到的错误行才却分号,可能是这行的上一行,也可能是下一行.
9、error: #65: expected a ";"和 error: #20: identifier "xxxx" is undefined一块出现,而且后面的error: #20错误可能一大堆
描述:这个错误对于第一次遇上的人来说绝对是个噩梦,当错误出现,满怀希望的双击错误提示,来到错误行时却愕然发现,错误行绝对没有错,于是找找错误行的上一行,下一行,没有错误,再找上上行,下下行...让人无比郁闷的事情出现了:编译提示的所有错误行都不可能有错误出现.其实这最可能是你在.h文件声明外部变量或者函数时,没有在声明语句的最后加分号!如果你有很多模块,如main.c,lcd.c,key.c...有很多头文件,如lcd.h,key.h,若是在lcd.h文件声明函数时没有加分号,那么这种错误可能定为到main.c中,所以要检查所有头文件.
解决方法:仔细检查.h文件,将分号补上.
10、error: L6200E: Symbol flagu multiply defined (by uart0.o and main.o).
描述:变量(也是一种符号)flagu多处定义(在uart0.c中和main.c都定义了).通常错在全局变量定义重复.比如:在main.c中定义全局变量flagu:
uint8 flagu=0;
在uart0.c中也用到该变量,于是声明此变量,我通常都是先复制定义的变量再在变量前面加关键字extern修饰:
extern uint8 flagu=0;
然后编译,就会出现上面的连接错误,原因在于,我在uart0.c中是又定义了一个变量,而不是声明变量,因为我给变量赋了初值"flagu=0",这样就重复定义了变量flag.正确的声明方法是去掉赋值部分:
extern uint8 flagu;
解决办法:找到重复定义的变量,看情况修改一处.
11、error: #159: declaration is incompatible with previous "wr_lcd" (declared at line 40)
描述:在wr_lcd函数还没有声明之前就已经使用了.多出现在两种情况:第一种,wr_lcd函数体还没有写,就已经用到了它,这种情况多出现在写一个程序的大体结构中,只是简单写一下框架.第二种情况比较常见,函数a调用函数b,但函数b的函数体在函数a的下面:
void a(void) //函数a的实体
{
b(); //调用函数b
}
void b(void) //函数b的实体
{
...
}
这样如果点编译,就会产生error: #159的错误,因为当函数a调用函数b时,发现在这之前都没有函数b的任何声明.
解决方法:在函数a调用函数b之前,对函数b进行声明,如:
void b(void); //对函数b进行声明
void a(void) //函数a的实体
{
b(); //调用函数b
}
void b(void) //函数b的实体
{
...
}
12、 error: #137: expression must be a modifiable lvalue
描述:表达式必须是一个可以修改的左值.主要出现在这种现象:
a=NUM;
NUM是一个数值或表达式,a为一个变量,但a被定义为像const这种不可更改的类型,导致NUM不能赋值给变量a.
解决方法:要么放弃赋值,要么修改变量属性.
13、error: #18: expected a ")"
如果是出现在c文件中, 多半是因为少了一个")",或者错误行有编译器不识别的字符
如果出现在头文件中,错误行又是一个函数声明,多半是因为在函数声明中有编译器不认识的字符
收集问题的目的是为了不再次犯错,提高开发效率。
来源:https://blog.csdn.net/qq_26575553/article/details/89487426