1.往上找教程,下载并移植CANFestival源码。
2.需要自己编写canSend()、getElapsedTime()、setTimer()函数;
canSend() ,作用是发送can数据,最终canfestival库发送数据,都会调用canSend()函数.
getElapsedTime(),作用是软件定时器的修正(通过一个硬件定时器,来模拟多个软件定时器).
setTimer(),作用是改变硬件定时器的溢出周期.
3.第二部之前需要先对can进行参数配置、can初始化、can使能,这样调用canSend才会有作用。
也需要配置stm32定时器之后,getElapsedTime()、setTimer()才可以起作用,这样time硬件定时器才能为CANFestival提供一个时钟基准。
主要就是提前配置can底层和定时器底层。
1.can底层配置代码案例,.c文件如下:
#include "stm32f4xx.h"
#include "canfestival_can.h"
#include "canfestival.h"
/* CANOPEN字典 */
extern CO_Data masterObjdict_Data;
/* 功能: GPIO配置
参数: 无
返回值:无
*/
static void gpio_config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);//使能PORTA时钟
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_50MHz; //100MHz GPIO_Speed_100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOD, &GPIO_InitStructure); //初始化
GPIO_PinAFConfig(GPIOD,GPIO_PinSource0,GPIO_AF_CAN1); //复用为CAN1
GPIO_PinAFConfig(GPIOD,GPIO_PinSource1,GPIO_AF_CAN1); //复用为CAN1
}
/* 功能: 中断嵌套控制器配置
参数: 无
返回值:无
*/
static void nvic_config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 设置CAN接收中断,先占优先级2,从站优先级2 */
NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
/* 初始化中断 */
NVIC_Init(&NVIC_InitStructure);
}
/* 功能: CAN总线过滤器配置
参数: 无
返回值:无
*/
static void can_filter_config(void)
{
CAN_FilterInitTypeDef CAN_FilterInitStructure;
/* 配置过滤器0组,配置成标准标识符且低7位都为0时接受 */
CAN_FilterInitStructure.CAN_FilterNumber = 0; /* 设置过滤器组0 */
CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask; /* 屏蔽模式 */
CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit; /* 32位模式 */
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000; /* 在CANOpen中标准标识符的低7位表示节点ID */
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0004; /* 在CANOpen中只用标准标识符,数据帧/远程帧都有 */
CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000; /* 主节点ID为0 */
CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000; /* 标准帧 */
CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0; /* 过滤器关联到FIFO0 */
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; /* 使能过滤器 */
CAN_FilterInit(&CAN_FilterInitStructure);
}
/* 功能: can总线配置
参数: 无
返回值:无
*/
void CANOpen_can_config(void)
{
CAN_InitTypeDef CAN_InitStructure;
/* 配置IO */
gpio_config();
/* 中断嵌套控制器配置 */
nvic_config();
/* 配置CAN总线时钟 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
/* CAN1默认参数 */
CAN_DeInit(CAN1);
/* 将结构体填入默认参数 */
CAN_StructInit(&CAN_InitStructure);
/* 关闭时间触发模式 */
CAN_InitStructure.CAN_TTCM = DISABLE;
/* 关闭自动离线管理 */
CAN_InitStructure.CAN_ABOM = ENABLE;
/* 关闭自动唤醒 */
CAN_InitStructure.CAN_AWUM = ENABLE;
/* 自动重传 */
CAN_InitStructure.CAN_NART = DISABLE;
/* 禁止FIFO溢出时覆盖原报文 */
CAN_InitStructure.CAN_RFLM = DISABLE;
/* 关闭优先级取决于ID */
CAN_InitStructure.CAN_TXFP = DISABLE;
/* 正常模式 */
CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
/* 设置波特率:36MHz/9/(2+1+1)=1mbps */
CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;
CAN_InitStructure.CAN_BS1 = CAN_BS1_2tq;
CAN_InitStructure.CAN_BS2 = CAN_BS2_1tq;
CAN_InitStructure.CAN_Prescaler = 9;
/* 初始化CAN总线 */
CAN_Init(CAN1, &CAN_InitStructure);
/* CAN总线过滤器配置 */
can_filter_config();
/* 接收挂起中断 */
CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);
}
/* can总线接收中断回调函数 */
void CAN1_RX0_IRQHandler(void)
{
CanRxMsg message;
Message Rx_Message;
/* 接收消息 */
CAN_Receive(CAN1, CAN_FIFO0, &message);
/* 组装canopen数据包 */
Rx_Message.cob_id = message.StdId; /* 功能码和节点ID */
Rx_Message.rtr = (message.RTR == CAN_RTR_DATA) ? 0 : 1; /* 标识符类型 */
Rx_Message.len = message.DLC; /* 数据包长度 */
memcpy(Rx_Message.data, message.Data, message.DLC); /* 数据 */
/* canopen数据包分配处理函数 */
canDispatch(&masterObjdict_Data, &Rx_Message);
}
/* 功能: CAN发送数据函数
参数: notused can总线端口
message canopen数据包
返回值: 0 成功
1 失败
*/
uint8_t canSend(CAN_PORT notused, Message *message)
{
uint32_t i = 0xFFFFFF;
CanTxMsg TxMessage;
uint8_t TransmitMailbox = 0;
/* 组装CAN数据包 */
TxMessage.DLC = message->len; /* 数据长度 */
memcpy(TxMessage.Data, message->data, message->len); /* 数据 */
TxMessage.IDE = CAN_ID_STD; /* 标准ID */
TxMessage.StdId = message->cob_id; /* 标识符 */
TxMessage.RTR = (message->rtr == CAN_RTR_DATA) ? 0 : 2; /* 数据帧 */
/* 发送数据包 */
TransmitMailbox = CAN_Transmit(CAN1, &TxMessage);
/* 等待发送成功 */
while((CAN_TransmitStatus(CAN1, TransmitMailbox) != CANTXOK) && --i);
/* 成功0 超时1 */
return (i != 0) ? 0 : 1;
}
.h文件如下
#ifndef __canfestival_can_H_
#define __canfestival_can_H_
/* 功能: can总线配置
参数: 无
返回值:无
*/
void CANOpen_can_config(void);
#endif
定时器.c文件如下:
#include "canfestival_timer.h"
// 下面函数是用于配制canfestival的唯一硬件定时器TIM14,
// 所以这个函数要在主函数中进行调用,然后传入的形参也是TIM14
void TIMConfig(TIM_TypeDef* TIMx, uint16_t TIM_Period, uint16_t TIM_Prescaler)
{
TIM_TimeBaseInitTypeDef TIM_BaseInitStructure;
//TIM_RepetitionCounter(TIM1_RCR)=0,每次向上溢出都产生更新事件
TIM_DeInit(TIMx);//初始化 TIM1寄存器
/*分频和周期计算公式:
Prescaler = (TIMxCLK / TIMx counter clock) - 1;
Period = (TIMx counter clock / TIM3 output clock) - 1
TIMx counter clock 为你所需要的 TXM 的定时器时钟*/
TIM_BaseInitStructure.TIM_Period = TIM_Period-1;//查数据手册可知,TIM1与 TIM8为16位自动装载
/*在 system_stm32f4xx.c 中设置的 APB2 Prescaler = 2 ,可知
*APB1时钟为168M/2*2,因为如果 APB1分频不为1,则定时时钟 x2*/
TIM_BaseInitStructure.TIM_Prescaler = TIM_Prescaler-1;//分频为10K
TIM_BaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_BaseInitStructure.TIM_RepetitionCounter = 0x0;
TIM_TimeBaseInit(TIMx, &TIM_BaseInitStructure);
//清中断,以免一启用中断后立即产生中断
TIM_ClearFlag(TIMx, TIM_FLAG_Update);
//使能TIM1中断源
TIM_ITConfig(TIMx, TIM_IT_Update, ENABLE);
//TIM1总开关:开启
TIM_Cmd(TIMx, ENABLE);//使能 TIM1定时器
}
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = TIM8_TRG_COM_TIM14_IRQn; //更新事件
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0; //抢占优先级0 原始0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应优先级1 原始1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //允许中断
NVIC_Init(&NVIC_InitStructure); //写入设置
}
// canfestival 定时器 timer14定时器
void TIM8_TRG_COM_TIM14_IRQHandler(void)
{
if(TIM_GetITStatus(TIM14,TIM_IT_Update)!=RESET)
{
TIM_ClearITPendingBit(TIM14, TIM_IT_Update); //清中断
TimeDispatch(); // canfestival的库
}
}
void setTimer(TIMEVAL value)
{
TIM14->ARR = TIM14->CNT + value;
}
TIMEVAL getElapsedTime(void)
{
return TIM14->CNT;
}
定时器.h文件如下:
#ifndef __canfestival_timer_H
#define __canfestival_timer_H
#include "sys.h"
#include "stdlib.h"
#include "stm32f4xx.h"
#include "canfestival.h"
void TIMConfig(TIM_TypeDef* TIMx, uint16_t TIM_Period, uint16_t TIM_Prescaler);
void NVIC_Configuration(void);
void setTimer(TIMEVAL value);
TIMEVAL getElapsedTime(void);
#endif
4.配置字典,生成.c和.h文件。
5.总体步骤如下:

浙公网安备 33010602011771号