一、开发环境与资料获取
使用keil开发,阔以使用VSCode下载一个扩展,看代码更舒服。
注意的是要去官方下载对应的pack芯片包,这样你才能使用keil开发。
去技术支持群找国民技术给的ftp链接/还有官网的奇怪论坛i2c啥。
二、debug时工具J-link的问题
1.如果安装的J-link版本高于keil自带的J-link版本,烧录程序会报错。
只需要去J-link的官网下载低版本的J-link驱动即可。
2.但是当J-ink的版本过低,而我们使用的芯片比较新的时候,开启debug也会报错,报错识别不到芯片内核似乎,已经解决找不到图片了。这时候你要自主选择你对应芯片的内核,比如我是M4。然后就可以解决。
三、配置ADC底层遇到问题
1.开发ADC,我是使用内部晶振。所以在ADC使用内部时钟HSI的时候,发现代码会卡在等待ADC启动。
发现是因为用了老版本的ADC库,老版本的ADC似乎还没解决这个问题。去找AE拿最新demo,把官方ADC的库替换之后,即可正常跑。
2.公司的架构代码里面有1ms的操作线程,使用的时候,没有关心到我删去了外部晶振。所以系统时钟似乎自动变成了4MHZ。而1ms线程使用的是108MHZ系统时钟,所以出现定时时间过长,程序跑的极为缓慢。
解决方法:修改系统时钟为HSI内部高速时钟,并且进行倍频至108MHZ。
去官方找到RCC设置的demo文件。进行CV。
注意开发的过程中一定要看清楚并且修改sysclock,看清楚自己的时钟选的是啥,非常重要!delay啥的都会变快或者变慢。
3.ADC的配置方面,要注意开启和关闭ADC。
4.AD数据采样方面。将采样到的AD数据可以存入一个长一点的数组如buffer[128]等,然后进行4个取一次平均啥的;或者去掉最大和最小值,然后再求平均。防止电压突变。
/*********************************************************
函数名: unsigned int ADCRead()
描 述: ADC转换程序,转换10次,去掉最小值和最大值,求8次平均值
输入值: 无
输出值: 无
返回值: data—ADC结果
**********************************************************/
unsigned int ADCRead()
{
unsigned int max, min, sum, ad_temp;
unsigned char i;
unsigned int data;
max = 0x00;
min = 0xffff;
sum = 0x00;
for (i=0; i<10; i++)
{
ad_temp = ADCConvert();
if (ad_temp > max)
{
max = ad_temp;//替换最大值
}
if (ad_temp < min)
{
min = ad_temp;//替换最小值
}
sum += ad_temp;
}
sum -= min;
sum -= max;
data = sum >> 3; //除以8,取平均值
return data;
}
四、硬件方面
1.因为硬件设计问题即对应ADC的IO可能电压被后面的电路拉走了,后面电阻给太大了,导致ADC在读取电压的时候,AD值为0。把后面电路断开,ADC就可以正常运行了。
最终发现是USB供电,电流不足的问题。换上DCsource供电,问题解决。
2.芯片的电源与地最好都要连,这边工程师漏连了,开发过程似乎没啥问题,不过后面飞线了。
3.看手册,注意有些引脚不能悬空。
4.三色led没有串联电阻,导致IO输出电压被拉低,可能是这个问题。
最终发现是USB供电,电流不足的问题。换上DCsource供电,问题解决。
5.第一板块记得叫硬件工程师留ADC的TP点。DCsource不够的时候,记得留3.3V电源点,不然还要自己焊接。
6.非常非常重要的,不要用usb口供电,用DCsource供电!因为DCsource有限,懒的去借。直接焊接了拓展小板子,USB3.3V供电。导致ADC读取电压有问题;芯片GPIO输出能力受限,电压降低至2.0多甚至更低;
7.TP芯片电压时,可以把绿油划开来测电压。
8.测试ADC的读取的电压是否正确时,可以直接用电压表接到对应电阻或电容地方来测试电压,根据公式和参考电压选择的不同来算。
五、keil5的debug的学习
1.把数组添加到watch窗口后,可以把名字里面的"[]"去掉,就可以一次性看所有的数组数据了。
2.单步运行,进入函数内部运行,跳出函数运行等
六、软件方面学习
1.switch从0开始进入循环
2.#define宏定义语句可以直接后面加函数,逗号隔开
3.读取ADC的AD值时,需要有一些电路中的补偿值(offset),这些补偿值比较小;还有需要做一些小数运算。基于这些,可以使用左右移动来提高计算,比较的精度。比如先左移13位,计算完后再右移7位,留6位进行比较;右移13位直接作为结果。
4.尽量少在MCU中使用浮点运算,比较占用运行内存。多使用移位运算辅助计算or比较。
5.64位有符号整数除以32位有符号整数有高效。在455单片机上运行一次要20US左右,太久了。
汇编程序:无符号64位除32位的除法子程序(-百度经验 (baidu.com)
因为不是固定除数,所以不能用移位,循环减更慢。所以使用汇编代码更加快速。
6.不同单片机的定义数据变量是不同的位数。不知道怎么查看。这个要注意一下。然后不同数据类型的对比与运算好像是向上兼容再做运算。
七、开发CAN通信
1.注意CAN通信波特率的计算。翻页AN查找波特率的计算。要注意CAN通信所使用的时钟。
2.过滤器标识符的运用配置问题。使用标志位暂时替代。注意在开发CAN通信中,常常会有很多的ID,所以需要过滤一部分不需要的ID。未解决。
没有使用芯片自带的过滤器,编写代码解决。
3.CAN通信的数据在对应的结构体就可以读取,数据存在sram中。
4.在发送数据的过程中,遇到了要将电压,电流数据分为高位,低位发送到BMS端。
而我定义的存储电压和电流的变量是32位的(如下图),因为为了提高精度,做了移位处理。
所以我面临一个问题:如何将32位的数据的高低字节分别存入1个字节(即8位)?
在编写代码前,复习了下啥是高位,啥是低位,如下
比如0xFD即1111 1101 。从右到左边,是从低位到高位。
所以先将我的32位数据*10扩大精度,然后再右移6位,变回比原来的数据大10倍的数据。然后开始做取出低字节and高字节的操作。运用位运算与,将低字节的8位数据取出来。再将原本的数据右移8位,将原本数据的高8位移到低8位,再用运算与取出高8位存入低8位。
而hal_CAN_TxMessages.Data[0]是个8位大的变量。
5.在做复杂计算的时候,若有相同的部分,可以拿出来定义一个变量,避免程序重复的计算节省时间。如上图我定义了Vout与Iout。
八、PWM开发问题
项目需要一个PWM波来控制电流的输出,以为简单的配置即可,以为推挽输出的能力非常足够,实则不是。
我配置了复用推挽输出,估计是高电平输出能力不足,导致电流有几十mA的跳变,这对于项目非常不行。测试了底板转换电路;测试了小卡3.3V与12V供电是否稳定,电源的波动也会影响到PWM波输出的电压;最终拿来了一台信号发生器,将小卡PWM输出断开,接上信号发生器,发现电流稳定几mA输出。推测PWM有隐藏问题。
最终将PWM配置为上拉+复用推挽输出。解决了这个问题。
PWM上拉可以提高高电平的输出能力。
九、移位计算的精度问题
遇到了调整电池电压1V,输出的电流却没有调整,因为我们的反馈是ADC测试Vout的电压,根据电压以及电流算出实时的功率,与目标功率进行对比,然后实现恒功率。推测是精度问题。
unsigned int Iset_target_max_U5F6;
unsigned int Iset_target_max_U5F6_a;
unsigned int CONSTANT_POWER=2250;
unsigned int meas_Vout_value_U6F6=110*64;
int main()
{
Iset_target_max_U5F6 = ((((CONSTANT_POWER * (1 << 12)) / meas_Vout_value_U6F6)));
Iset_target_max_U5F6_a = ((((CONSTANT_POWER * (1 << 6)) / meas_Vout_value_U6F6)) * (1 << 6));
printf("%d\n", Iset_target_max_U5F6);
printf("%d\n", Iset_target_max_U5F6_a);
return 0;
}
先移位再计算,提高精度。修改目标值的计算公式之后,精度提高了,并且正常。
另外,在做移位计算的时候,一定要注意数据的类型。unsigned int 是4个字节,32位,经得起移位12位。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/Xia996/article/details/134204006
|