STM32如何实现多个设备的主从机CAN通讯?
·
主从机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文件、代码)可以搜上面的号
更多推荐



所有评论(0)