2019.10.8
❤ 为了提高效率(为了应付中期。。。),首先从硬件设计上来突破。
2019.10.12
❤ 下面先把在总体思路里面确定的需求及机构分析搬过来
〇 需求及结构分析
1、能够通过CAN总线接收指令,并发送反馈信息 ;
STM32自带can模块,所以只需要一个can收发器就可以了,再加上can收发器的外围电路及120欧电阻。
2、能够控制4个电磁阀动作;
这个应该不难实现,只要留出4个IO口,然后选用合适的驱动芯片,搭建外围电路,配上指示灯,应该就可以,不过对于什么样的驱动芯片合适我还没有想法。
3、控制一个液压泵(我还不太确定,不过那个师兄的有的);
这个是师兄的设计里有,但是其具体作用和实现我还没仔细想。
4、留出串口进行调试;
这个就把串口预留出来就好了。
5、预留出其他通讯接口
考虑到今后的工作,可能需要和DSP或者FPGA进行通讯,所以留出相应的通讯接口。
6、其他
想到了再写。
〇 下面确定各个模块主要芯片的选型
1、STM32
在这里STM32需要的引脚不多,也没有太多的运算需求,就选用STM32F103C8T6就好了,48个引脚完全够用,而且体积小,好焊。
2、CAN收发器
关于CAN收发器我现在还不是特别的了解。备选方案有两个,一个是NXP的TJA1050,一个是Ti的SN65HVD230。
这两个芯片一个是我买的野火STM32开发板上的,一个是研旭DSP开发板上的,也就是说都是可以用的。经过对比我觉得这两个收发器的区别TJA1050是5V供电,数据引脚电压适应3.3V和5V,而SN65HVD230是3.3V供电,只适用于3.3V的设备,而且TJA1050比SN65HVD230便宜。因为我在使用F28335时使用的是SN65HVD230,为了将来和DSP进行通讯时提高兼容性,同时也简化供电方式,所以这里选用SN65HVD230。
3、电磁阀驱动芯片
关于驱动芯片这个首先要看电磁阀的参数。
但是我查了好久,就是没有找到ABS上的电磁阀参数。。。。。
只好凭感觉去选择驱动芯片。
师兄的课题里选用的是 MC33289。
这个芯片从性能上来说是够用的,而且有一些关于ABS的文献研究使用的就是这颗芯片。但是在查阅了很多资料和文献之后,我有了更好的选择。
L9349是专为汽车ABS系统的电磁阀控制设计的驱动芯片,它有四路输出,2路5A接ABS压力调节器的常开进油电磁阀,2路3A接常闭出油电磁阀,这样2块L9349就可以驱动ABS的8路电磁阀,并且电路更加简单,减小了控制器体积,提高了可靠性。
L9349是意法半导体公司的产品,其实和这款芯片功能类似的还有英飞凌公司的TLE6217
这两个无论从功能,参数,还是引脚定义方面几乎都一样,可以互相替换。
4、直流电机驱动芯片
ABS的液压调节器上面有一个直流电机,大概作用是给液压油提供压力,个头还挺大的,需要配备相应的驱动芯片。对于这个电机的控制我没查到什么资料,比如相关标准相关要求什么的。所以对于这个直流电机的控制策略还得等以后再查一查或者问问马老师。
关于这个直流电机驱动芯片的选择,师兄选用的是LMD18200T
这是一个美国国家半导体公司的产品,3A55V单H桥驱动器,优点是控制简单,通用性强,有必要的短路保护,过流保护,高温报警等安全措施。不过缺点是作为通用型直流电机驱动器,没有针对车用电子设备设计的一些信息反馈功能,而且外围电路稍显复杂。
经过查阅各种资料文献,我找到了一款在很多文献中提到的电机驱动芯片英飞凌公司的TLE6210
这款芯片是英飞凌专门为驱动ABS的直流电机设计的芯片,各种功能特性都非常适合,而且有相关的资料可以参考,但是当我想选用这个型号的驱动芯片后,想通过淘宝购买时发现供货的商家非常少。在英飞凌官网查询后发现,这个型号的芯片早在2010年就已经停产了。
我能怎么办我也很无奈呀。
于是我只好寻找他的替代型号。
于是有两款芯片进入了我的法眼。
第一个是英飞凌的TLE9201,第二个是意法半导体的L9358
这两款芯片从功能和参数上来看都差不多,都是单H桥驱动芯片,可以驱动感性负载,都有必要的保护与反馈功能,都可以通过SPI总线对芯片进行参数设置,以及读取状态数据,都是为车用电气设备设计的驱动芯片,虽然是主要用于节气门阀和EGR阀,不是专用于ABS系统,不过从参数上来看是可以适用的。
❤ 2019.12.22
其实早就该更新,但是当时中期在即,为了应付中期,我先制作了一个未完成版,但是我的中期还是没有过。。。于是我痛定思痛,(又被老师要求做了一的多月的舵机控制器之后。。。),又把控制器的pcb重新设计了一下,下面先回忆一下设计过程中遇到的问题。
确定了主要芯片的选型,下面就是绘制原理图和pcb了。
〇 原理图和PCB的绘制
♣ 原理图绘制
首先是stm32的最小系统,这里我用欣师兄之前画的稍作修改,没什么难度,不过有一点我没有预料到的是,stm32c8t6的IO口差点不够用。。。(其实我是在完成PCB布局之后才进行分配IO口的,所以如果真的不够用那影响还挺大的。。。)在分配完所有的控制IO和通讯IO之后,我惊讶的发现居然没有多余的!还剩一个用于测试的LED等没地方放了!于是我只好把LED接在了PC13上,但是后来才知道,PC13用做普通IO口的话是有一定的限制的,这个我写在了stm32学习笔记(3)里面。
供电部分没什么可说的
can收发器部分
这个原理图不是官方文档里面的,我是照搬研旭F28335开发板上面的,最开始在舵机控制器上面用的时候,5,6,7,8引脚画反了,后来改过来了。。。
L9349的周边电路原理图我是参考网上的资料(具体的忘记了。。。)做的,其实没啥需要参考的,外围电路很简单。
直流电机驱动器L9958的资料就是参考的st的文档,这个稍微复杂一点。
♣ PCB绘制
首先是封装库的制作。
关于封装我有个地方没有注意到,就是驱动芯片的下面是这样的
需要和铺铜GND连接来散热。
在第一次做的那个不完整版里我没有拿到芯片,不知道后面的样子,所以做的封装库没有考虑接地的情况,后来来看是不能用的。
于是后来我把封装做成了这样
然后关于背部与gnd的连接,我还发现了个问题,我的理解中,这个接地一方面是为了增加散热面积,另一方面是有利于电流的回流,所以应该接在驱动电源的地端,也就是PowerGND。L9349没有什么问题,背部与PGND内部相连,我只要在外部把它们也连在一起就好了。但是L9958sb却不是这样,可能是这个封装比较特别,他的背部是内部与引脚1的GND相连的,因为引脚8是PGND,所以我觉得引脚1应该是DGND,官方资料给出的示例里面并没有用这个封装,所以也没有说到底应该怎么连,我担心的是如果我连错了,可能会使数字信号受到干扰,或者使驱动电流流入DGND使0R电阻烧毁。在仔细分析并与朱工交流以后,我决定还是把背部与PGND相连,然后使引脚1接入DGND但是要远离其他DGND且接近电源。
于是我得pcb长这个样子
做好之后是这样的
对比一下之前的赶工版,差别还是很大的。。。怪不得陈老板会鄙视我。。。
PCB制作完,下面该焊接,测试,编写程序了。
〇 PCB各模块测试
♣ 电源模块
包括12V转5V和5V转3.3V,这个没啥好说的,只要不短路就能正常工作。
♣ STM32最小系统
这个问题也不大,因为我留了个测试用的LED灯,所以编写一段程序,能使LED闪烁就说明stm32能正常工作。
这里用我新学的Cube+HAL库来完成。(我也是第一次用Cube+HAL库,学习的过程我放在STM32学习笔记(2)里面了。)
配置
代码
结果
没有问题。
♣ CAN总线收发
这个相对来说要稍微复杂一点,我在STM32学习笔记(2)里面详细记录了学习的过程,这里就不再赘述了。
首先还是Cube里面的配置。
IO配置
时钟配置
can模块参数配置
中断配置
然后工程信息,最后generate。
用keil打开,编译。
然后就是配置can模块的初始化参数,因为我在之前学习can的时候都配置过,这里就直接复制了。
/* USER CODE BEGIN CAN_Init 0 */
CAN_FilterTypeDef sFilterConfig; //建立can过滤器配置结构体
/* USER CODE END CAN_Init 0 */
/* USER CODE BEGIN CAN_Init 2 */
//配置can过滤器
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.SlaveStartFilterBank = 14;
if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
{
/* Filter configuration Error */
Error_Handler();
}
//开启can模块
if (HAL_CAN_Start(&hcan) != HAL_OK)
{
/* Start Error */
Error_Handler();
}
//开启can中断
if (HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
{
/* Notification Error */
Error_Handler();
}
//配置发送邮箱初始信息
TxHeader.RTR = CAN_RTR_DATA;
TxHeader.IDE = CAN_ID_STD;
TxHeader.StdId = std_id;
TxHeader.TransmitGlobalTime = DISABLE;
TxHeader.DLC = 8;
/* USER CODE END CAN_Init 2 */
然后把can的驱动复制过来,并在main.c里include,再在主循环里添加语句
//测试can接收
if(MsgAvailable == 1)
{
CanTestSendBack();
}
OK,编译,下载,测试,木有问题~
♣ L9349电磁阀驱动测试
其实理论上,我应该先调试剩下的通讯端口,包括串口和spi总线,但是这两个通讯用处不大,串口是我预留用来调试的,spi是L9958用来反馈状态信息的,都不是必须的,所以这里(为了赶时间。。)我先不调了。
首先在Cube里配置IO口
Generate,打开,编译。
然后添加初始化程序和测试程序。
void Valve_Init(void)
{
//将电磁阀驱动器的驱动引脚置低
HAL_GPIO_WritePin(RR_NO_DRIVE_GPIO_Port,RR_NO_DRIVE_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(LF_NC_DRIVE_GPIO_Port,LF_NC_DRIVE_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(RF_NC_DRIVE_GPIO_Port,RF_NC_DRIVE_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(LF_NO_DRIVE_GPIO_Port,LF_NO_DRIVE_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(RF_NO_DRIVE_GPIO_Port,RF_NO_DRIVE_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(LR_NC_DRIVE_GPIO_Port,LR_NC_DRIVE_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(RR_NC_DRIVE_GPIO_Port,RR_NC_DRIVE_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(LR_NO_DRIVE_GPIO_Port,LR_NO_DRIVE_Pin,GPIO_PIN_RESET);
//将电磁阀驱动器的使能引脚置高
HAL_GPIO_WritePin(EN_FRONT_GPIO_Port,EN_FRONT_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(EN_REAR_GPIO_Port,EN_REAR_Pin,GPIO_PIN_SET);
}
void ValveTest(void)
{
HAL_GPIO_WritePin(RR_NO_DRIVE_GPIO_Port,RR_NO_DRIVE_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(LF_NC_DRIVE_GPIO_Port,LF_NC_DRIVE_Pin,GPIO_PIN_SET);
HAL_Delay(SUSTAIN_TIME);
HAL_GPIO_WritePin(LF_NC_DRIVE_GPIO_Port,LF_NC_DRIVE_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(RF_NC_DRIVE_GPIO_Port,RF_NC_DRIVE_Pin,GPIO_PIN_SET);
HAL_Delay(SUSTAIN_TIME);
HAL_GPIO_WritePin(RF_NC_DRIVE_GPIO_Port,RF_NC_DRIVE_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(LF_NO_DRIVE_GPIO_Port,LF_NO_DRIVE_Pin,GPIO_PIN_SET);
HAL_Delay(SUSTAIN_TIME);
HAL_GPIO_WritePin(LF_NO_DRIVE_GPIO_Port,LF_NO_DRIVE_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(RF_NO_DRIVE_GPIO_Port,RF_NO_DRIVE_Pin,GPIO_PIN_SET);
HAL_Delay(SUSTAIN_TIME);
HAL_GPIO_WritePin(RF_NO_DRIVE_GPIO_Port,RF_NO_DRIVE_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(LR_NC_DRIVE_GPIO_Port,LR_NC_DRIVE_Pin,GPIO_PIN_SET);
HAL_Delay(SUSTAIN_TIME);
HAL_GPIO_WritePin(LR_NC_DRIVE_GPIO_Port,LR_NC_DRIVE_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(RR_NC_DRIVE_GPIO_Port,RR_NC_DRIVE_Pin,GPIO_PIN_SET);
HAL_Delay(SUSTAIN_TIME);
HAL_GPIO_WritePin(RR_NC_DRIVE_GPIO_Port,RR_NC_DRIVE_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(LR_NO_DRIVE_GPIO_Port,LR_NO_DRIVE_Pin,GPIO_PIN_SET);
HAL_Delay(SUSTAIN_TIME);
HAL_GPIO_WritePin(LR_NO_DRIVE_GPIO_Port,LR_NO_DRIVE_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(RR_NO_DRIVE_GPIO_Port,RR_NO_DRIVE_Pin,GPIO_PIN_SET);
HAL_Delay(SUSTAIN_TIME);
}
没什么可说的,就是一个IO口的操作。
经过测试工作正常。
关于驱动器的反馈诊断功能暂时不是很急用,所以先不写了。
♣ L9958直流电机驱动测试
还是先在Cube里进行配置。
这里面的M_PWM引脚是用来调速的,应该配置为PWM输出,我把它放在了TIM4的输出引脚上,预留了PWM输出的功能,但是这里作为测试,先不考虑调速的问题,先配置为普通IO口。
Generate,打开,编译。
添加初始化程序和测试程序。
void Motor_Init(void)
{
//初始化
HAL_GPIO_WritePin(M_DI_GPIO_Port,M_DI_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(M_DIR_GPIO_Port,M_DIR_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(M_EN_GPIO_Port,M_EN_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(M_PWM_GPIO_Port,M_PWM_Pin,GPIO_PIN_RESET);
}
void MotorTest(void)
{
HAL_GPIO_WritePin(M_PWM_GPIO_Port,M_PWM_Pin,GPIO_PIN_SET);
while(1)
{
HAL_GPIO_WritePin(M_DIR_GPIO_Port,M_DIR_Pin,GPIO_PIN_SET);
HAL_Delay(2000);
HAL_GPIO_WritePin(M_DIR_GPIO_Port,M_DIR_Pin,GPIO_PIN_RESET);
HAL_Delay(2000);
}
}
没有问题。
关于PWM调速的程序,需要的时候再添加,spi总线的反馈程序也是。
整个控制器的硬件调试工作就到这里了。