stm32之CAN(一)

来源:互联网 发布:上海值得去的地方知乎 编辑:程序博客网 时间:2024/06/07 18:59

前面博客已经具体讲述了CAN的通信协议和stm32中bxCAN的通信协议,下面我们就具体实战啦!

首选一个简单的例程,是采用stm32中bxCAN的回环模式来进行测试。所谓的回环模式就是自己给自己发数据进行测试,想清楚的了解请看上一篇测试模式。当测试成功时开放板上LED1亮,并且可以通过串口打印。

下面就直接上代码:

main.c

#include "stm32f10x.h"#include "led.h"#include "usart1.h"void USART1_Configuration(void);void LED_GPIO_Configuration(void);void CAN_Configuration(void);void CAN_Test(void);typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus;volatile TestStatus TestRx;int main(void){USART1_Configuration();//初始化串口LED_GPIO_Configuration();//初始化LEDCAN_Configuration();//初始化CANprintf( "\r\n CAN 回环测试初始化成功...... \r\n" );CAN_Test();printf( "\r\n CAN 回环测试成功...... \r\n" );while(1);}/*CAN GPIO 和时钟配置 以及CAN的控制器和过滤器配置*/void CAN_Configuration(void){GPIO_InitTypeDef GPIO_InitStructure; CAN_InitTypeDef  CAN_InitStructure;CAN_FilterInitTypeDef  CAN_FilterInitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);                         /* CAN1 Periph clock enable */RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);/* Configure CAN pin: RX */               // PB8GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;             // 上拉输入GPIO_Init(GPIOB, &GPIO_InitStructure);/* Configure CAN pin: TX */               // PB9GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;         // 复用推挽输出GPIO_Init(GPIOB, &GPIO_InitStructure);/*CAN控制器初始化结构体*//* CAN register init */CAN_DeInit(CAN1);//can寄存器复位CAN_StructInit(&CAN_InitStructure);/* CAN cell init */CAN_InitStructure.CAN_TTCM=DISABLE; // 时间触发通信禁止CAN_InitStructure.CAN_ABOM=DISABLE; // 离线退出是在中断置位清0后退出CAN_InitStructure.CAN_AWUM=DISABLE; // 自动唤醒模式:清零sleepCAN_InitStructure.CAN_NART=DISABLE; // 自动重新传送报文,知道发送成功CAN_InitStructure.CAN_RFLM=DISABLE; // FIFO没有锁定,新报文覆盖旧报文  CAN_InitStructure.CAN_TXFP=DISABLE; // 发送报文优先级确定:标志符CAN_InitStructure.CAN_Mode=CAN_Mode_LoopBack; // 回环模式CAN_InitStructure.CAN_SJW=CAN_SJW_1tq; // 1tq、BS1、BS2的值跟波特率有关CAN_InitStructure.CAN_BS1=CAN_BS1_8tq;CAN_InitStructure.CAN_BS2=CAN_BS2_7tq;CAN_InitStructure.CAN_Prescaler=5;             // 分频系数为5CAN_Init(CAN1, &CAN_InitStructure);            // 初始化CAN1 /*CAN过滤器初始化结构体*//* CAN filter init */CAN_FilterInitStructure.CAN_FilterNumber=0;//初始化过滤器0CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;//标识符屏蔽位模式CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;//使用1个32位过滤器CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;//过滤器标识符为0x00000000CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//过滤器屏蔽标识符为0x00000000,即不屏蔽任何消息CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;CAN_FilterInitStructure.CAN_FilterFIFOAssignment=0;//过滤器FIFO0指向过滤器0CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;//使能过滤器CAN_FilterInit(&CAN_FilterInitStructure);}TestStatus CAN_Polling(void){CanTxMsg TxMessage;//定义消息发送结构体CanRxMsg RxMessage;//定义消息接收结构体uint32_t i = 0;uint8_t TransmitMailbox = 0;//定义发送邮箱号码变量/* transmit */TxMessage.StdId=0x11;// 设定标准标识符(11位,扩展的为29位)TxMessage.RTR=CAN_RTR_DATA;// 传输消息的帧类型为数据帧(还有远程帧)TxMessage.IDE=CAN_ID_STD;// 消息标志符实验标准标识符TxMessage.DLC=2;  // 发送两帧,一帧8位TxMessage.Data[0]=0xCA;// 第一帧数据TxMessage.Data[1]=0xFE;// 第二帧数据TransmitMailbox=CAN_Transmit(CAN1, &TxMessage);//CAN_Transmit()的返回值为所使用的的邮箱的号码,如果没有空邮箱返回CAN_NO_MBi = 0;// 用于检查消息传输是否正常while((CAN_TransmitStatus(CAN1, TransmitMailbox) != CANTXOK) && (i != 0xFF)){i++;}i = 0;// 检查返回的挂号的信息数目while((CAN_MessagePending(CAN1, CAN_FIFO0) < 1) && (i != 0xFF)){i++;}/* receive *///初始化接收RxMessage.StdId=0x00;//RxMessage.IDE=CAN_ID_STD;//消息标志符实验标准标识符RxMessage.DLC=0;//数据域为0个帧RxMessage.Data[0]=0x00;RxMessage.Data[1]=0x00;CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);if (RxMessage.StdId!=0x11){return FAILED;  }if (RxMessage.IDE!=CAN_ID_STD){return FAILED;}if (RxMessage.DLC!=2){return FAILED;  }/* 判断发送的信息和接收的信息是否相等 */if ((RxMessage.Data[0]<<8 | RxMessage.Data[1])!=0xCAFE){return FAILED;}//printf("receive data:0X%X,0X%X",RxMessage.Data[0], RxMessage.Data[1]);  return PASSED; /* Test Passed */}void CAN_Test(void){TestRx = CAN_Polling();if (TestRx == FAILED){    LED1( OFF );// LED1 OFF }else{    LED1( ON );  // LED1 ON;}}
usart1.h

#ifndef __USART1_H#define__USART1_H#include "stm32f10x.h"#include <stdio.h>void USART1_Configuration(void);int fputc(int ch, FILE *f);void USART1_printf(USART_TypeDef* USARTx, uint8_t *Data,...);

usart1.c

#include "usart1.h"#include <stdarg.h>void USART1_Configuration(void){GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;/* config USART1 clock */RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);/* USART1 GPIO config *//* Configure USART1 Tx (PA.09) as alternate function push-pull */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);    /* Configure USART1 Rx (PA.10) as input floating */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA, &GPIO_InitStructure);  /* USART1 mode config */USART_InitStructure.USART_BaudRate = 115200;USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_Parity = USART_Parity_No ;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART_Init(USART1, &USART_InitStructure); USART_Cmd(USART1, ENABLE);}int fputc(int ch, FILE *f){/* 将Printf内容发往串口 */USART_SendData(USART1, (unsigned char) ch);while (!(USART1->SR & USART_FLAG_TXE));return (ch);}static char *itoa(int value, char *string, int radix){int     i, d;int     flag = 0;char    *ptr = string;/* This implementation only works for decimal numbers. */if (radix != 10){    *ptr = 0;    return string;}if (!value){    *ptr++ = 0x30;    *ptr = 0;    return string;}/* if this is a negative value insert the minus sign. */if (value < 0){    *ptr++ = '-';    /* Make the value positive. */    value *= -1;}for (i = 10000; i > 0; i /= 10){    d = value / i;    if (d || flag)    {        *ptr++ = (char)(d + 0x30);        value -= (d * i);        flag = 1;    }}/* Null terminate the string. */*ptr = 0;return string;} /* NCL_Itoa */void USART1_printf(USART_TypeDef* USARTx, uint8_t *Data,...){const char *s;int d;   char buf[16];va_list ap;va_start(ap, Data);while ( *Data != 0)     // 判断是否到达字符串结束符{                          if ( *Data == 0x5c )  //'\'{  switch ( *++Data ){case 'r':          //回车符USART_SendData(USARTx, 0x0d);Data ++;break;case 'n':          //换行符USART_SendData(USARTx, 0x0a);Data ++;break;default:Data ++;break;} }else if ( *Data == '%'){  //switch ( *++Data ){case 's':  //字符串s = va_arg(ap, const char *);for ( ; *s; s++) {USART_SendData(USARTx,*s);while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );}Data++;break;case 'd'://十进制d = va_arg(ap, int);itoa(d, buf, 10);for (s = buf; *s; s++) {USART_SendData(USARTx,*s);while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );}Data++;break; default:Data++;    break;} } /* end of else if */else USART_SendData(USARTx, *Data++);while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );}}

led.h

#ifndef __LED_H#define__LED_H#include "stm32f10x.h"#define ON  1#define OFF 0#define LED1(a)if (a)\GPIO_SetBits(GPIOB,GPIO_Pin_5);\else\GPIO_ResetBits(GPIOB,GPIO_Pin_5)#define LED2(a)if (a)\GPIO_SetBits(GPIOD,GPIO_Pin_6);\else\GPIO_ResetBits(GPIOD,GPIO_Pin_6)#define LED3(a)if (a)\GPIO_SetBits(GPIOD,GPIO_Pin_3);\else\GPIO_ResetBits(GPIOD,GPIO_Pin_3)void LED_GPIO_Configuration(void);#endif 

led.c

#include "led.h"void LED_GPIO_Configuration(void){GPIO_InitTypeDef GPIO_InitStructure;//定义GPIO初始化结构体GPIO_InitStructureRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOD ,ENABLE);//开启RCC时钟/*对LED的IO口进行设置*/GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_3 | GPIO_Pin_6;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB ,&GPIO_InitStructure);GPIO_Init(GPIOD ,&GPIO_InitStructure);   /*是LED灭*/GPIO_ResetBits(GPIOB,GPIO_Pin_5);GPIO_ResetBits(GPIOD,GPIO_Pin_3);GPIO_ResetBits(GPIOD,GPIO_Pin_6);}


0 0