CAN控制器通过两根线上的电位差来判断总线电平
can.h
#can.h
#include"stm32f2xx.h"
#ifndef __CAN_H_
#define __CAN_H_
void CAN_Mode_Config(u8 CAN_BS1_xtq, u8 CAN_BS2_ytq, u16 Prescaler);
u8 CAN_Send_Msg(u8 *msg, u8 len);
u8 CAN_Receive_Msg(u8 *buf);
#endif
can.c
#include"stm32f2xx.h"
#include"stm32f2xx_can.h"
#include"can.h"
void CAN_Mode_Config(u8 CAN_BS1_xtq, u8 CAN_BS2_ytq, u16 Prescaler)
{
GPIO_InitTypeDef GPIO_InitStructure;
CAN_InitTypeDef CAN_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); //使能AHB1外设时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); //使能CAN1时钟
//GPIO初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_CAN1);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_CAN1);
//CAN初始化
CAN_InitStructure.CAN_ABOM = DISABLE; //软件自动离线管理
CAN_InitStructure.CAN_AWUM = DISABLE; //睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
CAN_InitStructure.CAN_BS1 = CAN_BS1_xtq; //时间段1的时间单元,取值在CAN_BS1_1tq~CAN_BS1_16tq
CAN_InitStructure.CAN_BS2 = CAN_BS2_ytq; //时间段2的时间单元,取值在CAN_BS2_1tq~CAN_BS2_8tq
CAN_InitStructure.CAN_Mode = CAN_Mode_Normal; //模式设置,普通模式
CAN_InitStructure.CAN_NART = ENABLE; //禁止报文自动传送
CAN_InitStructure.CAN_Prescaler = Prescaler; //分频系数(Fdiv)为brp+1
CAN_InitStructure.CAN_RFLM = DISABLE; //报文不锁定,新的覆盖旧的
CAN_InitStructure.CAN_SJW = CAN_SJW_1tq; //重新同步跳跃时间单元,CAN_SJW_1tq~CAN_SJW_4tq
CAN_InitStructure.CAN_TTCM = DISABLE; //非时间触发通信模式
CAN_InitStructure.CAN_TXFP = DISABLE; //优先级由报文标识符决定
CAN_Init(CAN1, &CAN_InitStructure);
//筛选初始化
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; ////激活过滤器0
CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_FilterFIFO0; //过滤器0关联到FIFO0
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_FilterMode = CAN_FilterMode_IdMask; //屏蔽模式
CAN_FilterInitStructure.CAN_FilterNumber = 0; //过滤器0
CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit; //
CAN_FilterInit(&CAN_FilterInitStructure);
CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE); //fifo0的中断
NVIC_InitStructure.NVIC_IRQChannel = CAN1_TX_IRQn; //stm..xx.h,发送中断
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
NVIC_Init(&NVIC_InitStructure);
}
//开始发送
u8 CAN_Send_Msg(u8 *msg, u8 len) //msg为数据,len为长度
{
u8 mbox; //邮箱
u16 i = 0;
CanTxMsg TXmessage; //can发送结构体
TXmessage.DLC = len; //数据个数,不能超过8个
TXmessage.ExtId = 0x12; //扩展标示符
TXmessage.IDE = CAN_ID_STD; //帧类型是标准帧,与这里的标准标示符和扩展标示符无关
//TXmessage.IDE = CAN_ID_EXT; //这里的帧类型也可以设置为扩展帧,在USB_CAN那里设置标准帧,传输记录中会有
TXmessage.RTR = CAN_RTR_DATA; //...can.h,传送的是数据帧
TXmessage.StdId = 0x12; //标准标示符
for(i = 0; i < len; i++)
{
TXmessage.Data[i] = msg[i];
}
mbox = CAN_Transmit(CAN1, &TXmessage); //返回当前邮箱
while((CAN_TransmitStatus(CAN1, mbox) == CAN_TxStatus_Failed)&&(i < 0xFFF))
{
i++; //等待发送结束完成
}
if(i >= 0xFFF)
{
return 1;
}
return 0;
}
u8 CAN_Receive_Msg(u8 *buf)
{
CanRxMsg RXmessage; //can接收结构体
u16 i = 0;
while(CAN_MessagePending(CAN1, CAN_FIFO0) == 0) //查询接收状态位,看是否由信息(报文)到达
{
return 0; //没有接收到数据,直接退出,看CAN_FIFO0中是否有数据
}
CAN_Receive(CAN1, CAN_FIFO0, &RXmessage); //接收信息(报文),将CAN_FIFO0中的数据通过can1拷贝到RXmessage结构体中
for(i = 0; i < RXmessage.DLC; i++)
{
buf[i] = RXmessage.Data[i];
}
return RXmessage.DLC;
}
led.h
#include"stm32f2xx.h"
#ifndef __LED_H
#define __LED_H
void LED_Init(void);
void Delay(vu32 nCount);
void CTL_LED(u8 LED_NUM, u8 OFF_ON);
#endif
led.c
#include"led.h"
#include"stm32f2xx.h"
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //led灯做输出,不用复用
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //GPIO_OType_PP表示推挽方式输出,GPIO_OType_OD表示开漏
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_SetBits(GPIOD, GPIO_Pin_12|GPIO_Pin_11);
}
void Delay(vu32 nCount)
{
for(; nCount != 0; nCount--);
}
#if 1
void CTL_LED(u8 LED_NUM, u8 OFF_ON)
{
switch(LED_NUM)
{
case 0:
if(OFF_ON == 1)
{
GPIO_ResetBits(GPIOD, GPIO_Pin_11);
}
else
{
GPIO_SetBits(GPIOD, GPIO_Pin_11);
}
break;
case 1:
if(OFF_ON == 1)
{
GPIO_ResetBits(GPIOD, GPIO_Pin_12);
}
else
{
GPIO_SetBits(GPIOD, GPIO_Pin_12);
}
break;
default:
//GPIO_ResetBits(GPIOF,GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10);
GPIO_SetBits(GPIOD,GPIO_Pin_11|GPIO_Pin_12);
break;
}
}
#endif
main.c
#include"stm32f2xx.h"
#include"can.h"
#include"led.h"
int main(void)
{
u8 res;
u8 key;
u8 canbuf[8] = {0}; //这里因为不知道从USB_CAN发的是什么,只需初始化为0即可
u8 a[8] = {02, 02, 02, 02, 02, 02, 02, 02}; //这里的02和2一样,12是0c
LED_Init();
Delay(168);
CAN_Mode_Config(CAN_BS1_8tq, CAN_BS2_6tq, 8); //此时CAN波特率为:30000/(1+8+6)*8 = 250kbps
while(1)
{
//1.接收数据
key = CAN_Receive_Msg(canbuf);
//2.解析数据
if(key == 0)
{
CTL_LED(1, 0); //开始的时候,没有接收到数据,故左边灯亮
}
else if(key > 0) //当接收到数据时,开始执行这一步
{
//3.发送数据给PC
CTL_LED(1, 1);
res = CAN_Send_Msg(a, 8);
if(res == 0)
{
CTL_LED(0, 1); //若数据发送成功,点亮led灯0
}
else
{
CTL_LED(1, 0); //若数据发送失败,熄灭led灯1
}
}
}
//开始的时候,没有接收到数据,故左边灯亮,当接收到数据时,开始执行发送数据函数,若发送成功,右边灯亮,
//若数据发送失败,熄灭led灯1
//问题:数据发送成功和失败的判断:是否合理?左边的灯会一直亮
//结合上面程序,将没有接收到数据时灯灭,数据发送时灯亮,可知数据发送成功,
//问题:can程序实验代码不显示接收?而且和发送数据框的数据无关?
/*
while(1)
{
res = CAN_Send_Msg(a, 8);
if(res == 0)
{
CTL_LED(0, 1); //若数据发送成功,点亮led灯0,即右边灯
key = CAN_Receive_Msg(canbuf);
if(key == 0)
{
CTL_LED(1, 1); //实验结果是,执行这一步
}
else if(key > 0)
{
Delay(5000);
//CTL_LED(1, 1); //灯1为左边的灯
}
}
else
{
Delay(5000);
//CTL_LED(1, 0); //若数据发送失败,点亮led灯1
}
}
*/
}