主从机can通讯(stm32)
基于STM32的CAN总线温度检测节点 的硬件设计与制作。1个主节点+3个从节点,每个节点均包含STM32最小系统、CAN通信模块、温度采集模块,能够稳定完成本地温度采集并通过CAN总线实现数据收发。
1、CAN 总线
CAN(Controller Area Network,控制器局域网),1983 年博世为汽车电子开发,是差分串行通信总线,多主仲裁、抗干扰强、实时性高,广泛用于汽车、工业 PLC、嵌入式设备。 核心特点:多主机、无主从区分;差分信号抗 EMI;硬件帧仲裁;错误自动检测重传;最远 10km 低速通信。
本系统选取的是闭环CAN总线网络。特点:高速、短距离,它的总线最大长度为40m,通信速度最高为1Mbps,总线的两端各要求有一个120 欧的电阻。如下图所示:
2、CAN 模块
CAN通信模块核心器件选用TJA1050 CAN收发器,该器件支持5kbps至1Mbps波特率,兼容CAN 2.0A/B协议,可将STM32内部CAN控制器的逻辑电平转换为总线差分信号,提升抗干扰能力。其具备热保护、短路保护功能,可避免总线故障损坏器件,且体积小、功耗低,适合节点模块化部署;总线两端配置120Ω终端电阻,抑制信号反射,保障长距离传输稳定性。
3、注意事项:
由于TJA1050 CAN收发器配置了120Ω终端电阻,在连接TJA1050 硬件之前,需要对其中两个TJA1050去掉120Ω终端电阻,保证是闭环CAN总线网络,这样信号传输就不会丢包。
4、器件清单
| stm32f103c8t6 | 4 |
| TJA1050 | 4 |
| DS18B20 | 4 |
| BEEP | 3 |
| LED | 4 |
| 电源模块 | 1 |
| OLED 屏幕 | 1 |
| 按键模块 | 2 |
5、主机原理图
6、从机原理图
7、主机代码
#include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "Key.h" #include "MyCAN.h" #include "STDIO.h" #include "ds18b20.h" #include "LED.h" uint8_t Keycount; uint8_t Keymode; uint32_t RxID; uint8_t RxLength; uint8_t RxData[8]; uint32_t TxID = 0x111; uint8_t TxLength = 8; uint8_t TxData[8] = {0x00, 0x00, 0x00}; float TA; float TB; float TC; float TD; char TA_buf[10]; char TB_buf[10]; char TC_buf[10]; char TD_buf[10]; uint8_t TA_s = 30; uint8_t TB_s = 30; uint8_t TC_s = 30; uint8_t TD_s = 30; void SHOW(void) { OLED_ShowString(1, 1, "A:"); OLED_ShowString(2, 1, "B:"); OLED_ShowString(3, 1, "C:"); OLED_ShowString(4, 1, "D:"); if(TA > TA_s) OLED_ShowString(1,10,"warning"); else OLED_ShowString(1,10,"normal "); if(TB > TB_s) OLED_ShowString(2,10,"warning"); else OLED_ShowString(2,10,"normal "); if(TC > TC_s) OLED_ShowString(3,10,"warning"); else OLED_ShowString(3,10,"normal "); if(TD > TD_s) OLED_ShowString(4,10,"warning"); else OLED_ShowString(4,10,"normal "); } float temp_data; float temp_data1[1]; int main(void) { OLED_Init(); Key_Init(); MyCAN_Init(); OLED_Clear(); DS18B20_Init(); BEEP_Init(); LED_Init(); while (1) { Keycount = Key_GetNum(); if(Keycount ==1){ OLED_Clear(); Keymode++; if(Keymode>4)Keymode = 0; } if(Keymode==0) { SHOW(); TD=(float)DS18B20_Get_Temp()/10.0f; TxData[0] = TA_s; TxData[1] = TB_s; TxData[2] = TC_s; MyCAN_Transmit(0X111, TxLength,TxData); MyCAN_Transmit(0X222, TxLength,TxData); MyCAN_Transmit(0X333, TxLength,TxData); if(TD > (float)TD_s){ LED_ON();BEEP_ON(); Delay_ms(10); } else{ LED_OFF();BEEP_OFF(); Delay_ms(10); } if (MyCAN_ReceiveFlag()) { MyCAN_Receive(&RxID, &RxLength, RxData); if(RxID == 0x111)//从机A TA = RxData[0] *10 + RxData[1] + (float)RxData[2]*0.1; if(RxID == 0x222)//从机B TB = RxData[0] *10 + RxData[1] + (float)RxData[2]*0.1; if(RxID == 0x333)//从机C TC = RxData[0] *10 + RxData[1] + (float)RxData[2]*0.1; sprintf(TA_buf,"%.1fC",TA);OLED_ShowString(1,3,TA_buf); Delay_ms(2); sprintf(TB_buf,"%.1fC",TB);OLED_ShowString(2,3,TB_buf); Delay_ms(2); sprintf(TC_buf,"%.1fC",TC);OLED_ShowString(3,3,TC_buf); Delay_ms(2); sprintf(TD_buf,"%.1fC",TD);OLED_ShowString(4,3,TD_buf); Delay_ms(2); } } Delay_ms(2); if(Keymode>0) { OLED_ShowString(1,3,"TA_H:"); OLED_ShowString(2,3,"TB_H:"); OLED_ShowString(3,3,"TC_H:"); OLED_ShowString(4,3,"TD_H:"); OLED_ShowNum(1,8,TA_s ,2); OLED_ShowNum(2,8,TB_s ,2); OLED_ShowNum(3,8,TC_s ,2); OLED_ShowNum(4,8,TD_s ,2); } if(Keymode==1) { OLED_ShowString(1,11,"<"); if(Keycount ==2){ TA_s++; if(TA_s>40)TA_s=20;} } if(Keymode==2) { OLED_ShowString(2,11,"<"); if(Keycount ==2){ TB_s++; if(TB_s>40)TB_s=20;} } if(Keymode==3) { OLED_ShowString(3,11,"<"); if(Keycount ==2){ TC_s++; if(TC_s>40)TC_s=20;} } if(Keymode==4) { OLED_ShowString(4,11,"<"); if(Keycount ==2){ TD_s++; if(TD_s>40)TD_s=20;} } } }8、从机代码
下面是从机A代码。从机B、C、D代码只需将CAN的ID改成不同的即可。
#include "stm32f10x.h" // Device header #include "Delay.h" #include "LED.h" #include "MyCAN.h" #include "ds18b20.h" #include <stdio.h> #include <stdlib.h> uint32_t RxID; uint8_t RxLength; uint8_t RxData[8]; uint32_t TxID = 0x222; uint8_t TxLength = 8; uint8_t TxData[8] = {0x00, 0x00, 0x00}; int Ttens, Tunits, Tdecimal; float temp_data; float temp_data1[1]; int temp_data_H; void extract_digits(float num, int *tens, int *units, int *decimal) { float abs_num = (num < 0) ? -num : num; int scaled = (int)(abs_num * 10.0f + 0.5f); *decimal = scaled % 10; // 小数位 *units = (scaled / 10) % 10; // 个位 *tens = (scaled / 100) % 10; // 十位 } int main(void) { DS18B20_Init(); LED_Init(); BEEP_Init(); MyCAN_Init(); while (1) { temp_data=(float)DS18B20_Get_Temp()/10.0f; if(temp_data > temp_data_H){ LED_ON();BEEP_ON(); Delay_ms(10); } else{ LED_OFF();BEEP_OFF(); Delay_ms(10); } temp_data1[0]=temp_data; extract_digits(temp_data1[0], &Ttens, &Tunits, &Tdecimal); TxData[0] = Ttens; TxData[1] = Tunits; TxData[2] = Tdecimal; MyCAN_Transmit(TxID, TxLength,TxData); if (MyCAN_ReceiveFlag()) { MyCAN_Receive(&RxID, &RxLength, RxData); if(RxID == 0x222)//从机A { temp_data_H = RxData[1]; } } Delay_ms(100); } }9、实物图
指导
如果需要全套源码(器件清单、含原理图、pcb文件、代码)可以搜上面的号