其实CAN总线是多主模式,并不是主从模式。我们平时称呼的主CAN,从CAN,其实除了称呼不同,在使用和功能上没有任何区别。
1.CAN 节点代码
can.c
//CAN初始化
//tsjw:重新同步跳跃时间单元.范围:CAN_SJW_1tq~ CAN_SJW_4tq
//tbs2:时间段2的时间单元. 范围:CAN_BS2_1tq~CAN_BS2_8tq;
//tbs1:时间段1的时间单元. 范围:CAN_BS1_1tq ~CAN_BS1_16tq
//brp :波特率分频器.范围:1~1024; tq=(brp)*tpclk1
//波特率=Fpclk1/((tbs1+1+tbs2+1+1)*brp);
//mode:CAN_Mode_Normal,普通模式;CAN_Mode_LoopBack,回环模式;
//Fpclk1的时钟在初始化的时候设置为42M,如果设置CAN1_Mode_Init(CAN_SJW_1tq,CAN_BS2_6tq,CAN_BS1_7tq,6,CAN_Mode_LoopBack);
//则波特率为:42M/((6+7+1)*6)=500Kbps
//返回值:0,初始化OK;
// 其他,初始化失败;
u8 CAN1_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
{
GPIO_InitTypeDef GPIO_InitStructure;
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
#if CAN1_RX0_INT_ENABLE
NVIC_InitTypeDef NVIC_InitStructure;
#endif
//使能相关时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能PORTA时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟
//初始化GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11| GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化PA11,PA12
//引脚复用映射配置
GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_CAN1); //GPIOA11复用为CAN1
GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_CAN1); //GPIOA12复用为CAN1
//CAN单元设置
CAN_InitStructure.CAN_TTCM=DISABLE; //非时间触发通信模式
CAN_InitStructure.CAN_ABOM=DISABLE; //软件自动离线管理
CAN_InitStructure.CAN_AWUM=DISABLE;//睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
CAN_InitStructure.CAN_NART=ENABLE; //禁止报文自动传送
CAN_InitStructure.CAN_RFLM=DISABLE; //报文不锁定,新的覆盖旧的
CAN_InitStructure.CAN_TXFP=DISABLE; //优先级由报文标识符决定
CAN_InitStructure.CAN_Mode= mode; //模式设置
CAN_InitStructure.CAN_SJW=tsjw; //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq~CAN_SJW_4tq
CAN_InitStructure.CAN_BS1=tbs1; //Tbs1范围CAN_BS1_1tq ~CAN_BS1_16tq
CAN_InitStructure.CAN_BS2=tbs2;//Tbs2范围CAN_BS2_1tq ~ CAN_BS2_8tq
CAN_InitStructure.CAN_Prescaler=brp; //分频系数(Fdiv)为brp+1
CAN_Init(CAN1, &CAN_InitStructure); // 初始化CAN1
//配置过滤器
CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器0
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位
CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;32位ID
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASK
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0
CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化
#if CAN1_RX0_INT_ENABLE
CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);//FIFO0消息挂号中断允许.
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占优先级0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* 中断设置 CAN1_RX1中断 */
NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占优先级2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
#endif
return 0;
}
//can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)
//len:数据长度(最大为8)
//msg:数据指针,最大为8个字节.
//返回值:0,成功;
// 其他,失败;
u8 CAN1_Send_Msg(u8* msg,u8 len)
{
//Txmessage.StdId = 0x00;
TxMessage.ExtId = 0x0314; //使用的扩展ID
TxMessage.IDE = CAN_ID_EXT; //扩展模式
TxMessage.RTR = CAN_RTR_DATA; //发送的是数据
TxMessage.DLC = 8; //数据长度为8字节
TxMessage.Data[0] = (uint8_t)DHT22_Data.temp;
TxMessage.Data[1] = (uint8_t)DHT22_Data.humi;
TxMessage.Data[2] = tplsb;
TxMessage.Data[3] = tpmsb;
TxMessage.Data[4] = Concentration;
TxMessage.Data[5] = Humidity;
TxMessage.Data[6] = BUF[0];
TxMessage.Data[7] = BUF[1];
// 发送两帧信息
}
//can口接收数据查询
//buf:数据缓存区;
//返回值:0,无数据被收到;
// 其他,接收的数据长度;
u8 CAN1_Receive_Msg(u8 *buf)
{
u32 i;
CanRxMsg RxMessage;
if( CAN_MessagePending(CAN1,CAN_FIFO0)==0)
return 0; //没有接收到数据,直接退出
CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);//读取数据
for(i=0;i<RxMessage.DLC;i++)
buf[i]=RxMessage.Data[i];
return RxMessage.DLC;
}
stm32f10x_it.c
void USB_LP_CAN1_RX0_IRQHandler(void)
{
/* 从邮箱读出报文 */
CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
/* 比较ID和数据是否为 0x1314 及 DCBA */
if( (RxMessage.ExtId == 0x1C00) && (RxMessage.IDE == CAN_ID_EXT) && (RxMessage.DLC == 0) )
flag = 0; //接收成功
else
flag = 0xff; //接收失败
}
void CAN1_RX1_IRQHandler(void)
{
/* 从邮箱读出报文 */
CAN_Receive(CAN1, CAN_FIFO1, &RxMessage);
/* 比较ID是否为 0x1010 */
if( (RxMessage.ExtId == 0x1010) && (RxMessage.IDE == CAN_ID_EXT) && (RxMessage.DLC == 1) && (RxMessage.Data[0] == 0x00))
C_flag = 0; //照明指令
else if( (RxMessage.ExtId == 0x1010) && (RxMessage.IDE == CAN_ID_EXT) && (RxMessage.DLC == 1) && (RxMessage.Data[0] == 0x01))
C_flag = 1; //通风指令
else if( (RxMessage.ExtId == 0x1010) && (RxMessage.IDE == CAN_ID_EXT) && (RxMessage.DLC == 1) && (RxMessage.Data[0] == 0x02))
C_flag = 2; //灌溉指令
else if( (RxMessage.ExtId == 0x1010) && (RxMessage.IDE == CAN_ID_EXT) && (RxMessage.DLC == 1) && (RxMessage.Data[0] == 0x03))
C_flag = 3; //卷帘指令
else
C_flag = 0xff;
}
main.c
void Control()
{
switch(c_flag)
case 0;.......break;
case 1;.......break;
case 2;.......break;
case 3;.......break;
}
2.CAN控制室代码
u8 CAN1_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
{
GPIO_InitTypeDef GPIO_InitStructure;
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
//使能相关时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能PORTA时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟
//初始化GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11| GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化PA11,PA12
//引脚复用映射配置
GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_CAN1); //GPIOA11复用为CAN1
GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_CAN1); //GPIOA12复用为CAN1
//CAN单元设置
CAN_InitStructure.CAN_TTCM=DISABLE; //非时间触发通信模式
CAN_InitStructure.CAN_ABOM=DISABLE; //软件自动离线管理
CAN_InitStructure.CAN_AWUM=DISABLE;//睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
CAN_InitStructure.CAN_NART=ENABLE; //禁止报文自动传送
CAN_InitStructure.CAN_RFLM=DISABLE; //报文不锁定,新的覆盖旧的
CAN_InitStructure.CAN_TXFP=DISABLE; //优先级由报文标识符决定
CAN_InitStructure.CAN_Mode= mode; //模式设置
CAN_InitStructure.CAN_SJW=tsjw; //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq~CAN_SJW_4tq
CAN_InitStructure.CAN_BS1=tbs1; //Tbs1范围CAN_BS1_1tq ~CAN_BS1_16tq
CAN_InitStructure.CAN_BS2=tbs2;//Tbs2范围CAN_BS2_1tq ~ CAN_BS2_8tq
CAN_InitStructure.CAN_Prescaler=brp; //分频系数(Fdiv)为brp+1
CAN_Init(CAN1, &CAN_InitStructure); // 初始化CAN1
//配置过滤器
CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器0
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位
CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;32位ID
CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASK
CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器0
CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化
CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE); //CAN通信中断使能
return 0;
}
void CAN_SetMsg_1(void)
{
//Txmessage.StdId = 0x00;
TxMessage.ExtId = 0x1800; //使用的扩展ID
TxMessage.IDE = CAN_ID_EXT; //扩展模式
TxMessage.RTR = CAN_RTR_DATA; //发送的是数据
TxMessage.DLC = 0; //数据长度为0
}
void CAN_SetMsg_2(void)
{
//Txmessage.StdId = 0x00;
TxMessage.ExtId = 0x1C00; //使用的扩展ID
TxMessage.IDE = CAN_ID_EXT; //扩展模式
TxMessage.RTR = CAN_RTR_DATA; //发送的是数据
TxMessage.DLC = 0; //数据长度为0
}
void CAN_SetMsg_Light(void)
{
//Txmessage.StdId = 0x00;
TxMessage.ExtId = 0x1010; //使用的扩展ID
TxMessage.IDE = CAN_ID_EXT; //扩展模式
TxMessage.RTR = CAN_RTR_DATA; //发送的是数据
TxMessage.DLC = 1; //数据长度为1
TxMessage.Data[0] = 0x00;
}
void CAN_SetMsg_Wind(void)
{
//Txmessage.StdId = 0x00;
TxMessage.ExtId = 0x1010; //使用的扩展ID
TxMessage.IDE = CAN_ID_EXT; //扩展模式
TxMessage.RTR = CAN_RTR_DATA; //发送的是数据
TxMessage.DLC = 1; //数据长度为1
TxMessage.Data[0] = 0x01;
}
void CAN_SetMsg_Irrigation(void)
{
//Txmessage.StdId = 0x00;
TxMessage.ExtId = 0x1010; //使用的扩展ID
TxMessage.IDE = CAN_ID_EXT; //扩展模式
TxMessage.RTR = CAN_RTR_DATA;//发送的是数据
TxMessage.DLC = 1; //数据长度为1
TxMessage.Data[0] = 0x02;
}
void CAN_SetMsg_Rolling(void)
{
//Txmessage.StdId = 0x00;
TxMessage.ExtId = 0x1010; //使用的扩展ID
TxMessage.IDE = CAN_ID_EXT; //扩展模式
TxMessage.RTR = CAN_RTR_DATA;//发送的是数据
TxMessage.DLC = 1; //数据长度为1
TxMessage.Data[0] = 0x03;
}
void CAN_SetMsg(void)
{
static float a = 0.5, b = 0.5, m;
m = a+b;
/* 打包报文 */
if(m == 1)
CAN_SetMsg_1();
else
CAN_SetMsg_2();
b = -b;
}
stm32f10X_it.c
void USB_LP_CAN1_RX0_IRQHandler(void)
{
/* 从邮箱读出报文 */
CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
/* 比较ID是否为 0x1314 */
if( (RxMessage.ExtId == 0x1314) && (RxMessage.IDE == CAN_ID_EXT) && (RxMessage.DLC == 8) )
flag = 0; //“主机1”接收成功
else
flag = 0xff; //接收失败
}
void CAN1_RX1_IRQHandler(void)
{
/* 从邮箱读出报文 */
CAN_Receive(CAN1, CAN_FIFO1, &RxMessage);
/* 比较ID是否为 0x0314 */
if( (RxMessage.ExtId == 0x0314) && (RxMessage.IDE == CAN_ID_EXT) && (RxMessage.DLC == 8) )
flag = 1; //“主机2”接收成功
else
flag = 0xff; //接收失败
}
void EXTI4_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line4) != RESET) //4线 光照指令按键
{
CAN_SetMsg_Light();
CAN_Transmit(CAN1, &TxMessage);
EXTI_ClearITPendingBit(EXTI_Line4); //清除中断标志位
}
}
void EXTI9_5_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line5) != RESET) //5线 通风指令按键
{
CAN_SetMsg_Wind();
CAN_Transmit(CAN1, &TxMessage);
EXTI_ClearITPendingBit(EXTI_Line5); //清除中断标志位
}
}
void EXTI15_10_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line13) != RESET) //13线 灌溉指令按键
{
CAN_SetMsg_Irrigation();
CAN_Transmit(CAN1, &TxMessage);
EXTI_ClearITPendingBit(EXTI_Line13); //清除中断标志位
}
if(EXTI_GetITStatus(EXTI_Line14) != RESET) //14线 卷帘指令按键
{
CAN_SetMsg_Rolling();
CAN_Transmit(CAN1, &TxMessage);
EXTI_ClearITPendingBit(EXTI_Line14); //清除中断标志位
}
}
图示:
欢迎指正谢谢!