在STM32f103上实现CANPrintf功能

  CAN初始化代码如下,这里没什么好讲的,可参考正点原子官方提供的例程。

#include "can.h"
#include <string.h>
#include "stm32f10x.h"
#include <stdarg.h>
#include <stdio.h>


u8 CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)
{

	  GPIO_InitTypeDef GPIO_InitStructure; 
	  CAN_InitTypeDef        CAN_InitStructure;
 	  CAN_FilterInitTypeDef  CAN_FilterInitStructure;
#if CAN_RX0_INT_ENABLE 
   	NVIC_InitTypeDef  NVIC_InitStructure;
#endif

	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PORTA时钟	                   											 

  	RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟	

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽
    GPIO_Init(GPIOA, &GPIO_InitStructure);		//初始化IO
   
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化IO
	  
 	//CAN单元设置
 	  CAN_InitStructure.CAN_TTCM=DISABLE;						
  	CAN_InitStructure.CAN_ABOM=DISABLE;						
  	CAN_InitStructure.CAN_AWUM=DISABLE;						 
  	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;				
  	CAN_InitStructure.CAN_BS1=tbs1; 
  	CAN_InitStructure.CAN_BS2=tbs2;
  	CAN_InitStructure.CAN_Prescaler=brp;            
  	CAN_Init(CAN1, &CAN_InitStructure);             

 	CAN_FilterInitStructure.CAN_FilterNumber=0;	  
   	CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; 
  	CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  
  	CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;
  	CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
  	CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;
  	CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
  	CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;
 	CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; 

  	CAN_FilterInit(&CAN_FilterInitStructure);//滤波器初始化
#if CAN_RX0_INT_ENABLE
	
	CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);	    
  
  	NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;   // 主优先级为1
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;          // 次优先级为0
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  	NVIC_Init(&NVIC_InitStructure);
#endif
	return 0;
}   
 
#if CAN_RX0_INT_ENABLE	//使能RX0中断
//中断服务函数			    
void USB_LP_CAN1_RX0_IRQHandler(void)
{
  	CanRxMsg RxMessage;
	int i=0;
    CAN_Receive(CAN1, 0, &RxMessage);
	for(i=0;i<8;i++)
	printf("rxbuf[%d]:%d\r\n",i,RxMessage.Data[i]);
}
#endif

//can发送一组数据(固定格式:ID为0X555,标准帧,数据帧)	
//len:数据长度(最大为8)				     
//msg:数据指针,最大为8个字节.
//返回值:0,成功;
//		 其他,失败;
u8 Can_Send_Msg(u8* msg,u8 len)
{	
  u8 mbox;
  u16 i=0;
  CanTxMsg TxMessage;
  TxMessage.StdId=0x555;		// 标准标识符 
  //TxMessage.ExtId=0x12;		// 设置扩展标示符 
  TxMessage.IDE=CAN_Id_Standard; // 标准帧
  TxMessage.RTR=CAN_RTR_Data;	 // 数据帧
  TxMessage.DLC=len;			// 要发送的数据长度
  for(i=0;i<len;i++)
  TxMessage.Data[i]=msg[i];			          
  mbox= CAN_Transmit(CAN1, &TxMessage);   
  i=0;
  while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++;	//等待发送结束
  if(i>=0XFFF)return 1;
  return 0;		

}

can_printf的代码如下,该部分代码主要由两部分构成,一是将格式化字符串及参数存储到调试消息缓冲区can_msg_buf中;二是将缓冲区中的调试信息发送到CAN总线,具体实现过程可以参考下面代码的注释。

#define CAN_MSG_BUF_SIZE 128    // 调试消息缓冲区大小 
char can_msg_buf[CAN_MSG_BUF_SIZE]; // 调试消息缓冲区

void can_printf(const char *fmt, ...)
{

    // 将格式化字符串及参数存储到调试消息缓冲区can_msg_buf中
    va_list args;
    va_start(args, fmt);
    vsnprintf(can_msg_buf, CAN_MSG_BUF_SIZE, fmt, args);
    va_end(args);

    //将缓冲区中的调试信息发送到CAN总线
    int strLength = strlen(can_msg_buf);
    int split = strlen(can_msg_buf) / 8;
    int remainder = strlen(can_msg_buf) % 8;
    u8 asciiArray[strLength];
    u8 canbuffer[8];
    u8 fdbc;
		  
    for (int i = 0; i < strLength ; i++)//不管是否超过8个字节先发一次数据,后期可以用来查看mailbox是否被占用
    {
        asciiArray[i] = (int)can_msg_buf[i];
    }

    for (int i = 0; i < 8; i++)
    {
        canbuffer[i] = asciiArray[i];
    }
		
    fdbc = Can_Send_Msg(canbuffer, 8); //can发送数据
    
    if (strLength > 8)//如果大于8个字节进行拆包,从弟9个数据开始发送
    {

        for (int i = 1; i < split ; i++)
        {

            for (int j = 0; j < 8; j++)
            {
                canbuffer[j] = asciiArray[i * 8 + j];
            }

            while (CAN_TransmitStatus(CAN1, 0) == CAN_TxStatus_Pending) //检查MailBox[0]是否空闲
            {
                //等待
            }
            
            fdbc = Can_Send_Msg(canbuffer, 8);
			//如果不检测mailbox的占用状态,在这里也可以加一个延时函数,但是一般不建议这样写
			//delay_ms(3);

        }

        if (remainder != 0)
        {

            for (int i = 0; i < 8; i++)
            {
                canbuffer[i] = 0;
            }

            for (int i = 0; i < remainder; i++)
            {
                canbuffer[i] = asciiArray[split * 8 + i];
            }
						
            while (CAN_TransmitStatus(CAN1, 0) == CAN_TxStatus_Pending) //检查MailBox[0]是否空闲
            {
                //等待
            }

            fdbc = Can_Send_Msg(canbuffer, 8);

        }
    }

}

主函数代码如下,就是每隔一段时间打印一句话,在这句话中有一个变量,实现类似于printf函数的功能。

#include "stm32f10x.h"
#include "can.h"
#include "delay.h"




int main(void)
{

    delay_init();
    CAN_Mode_Init(CAN_SJW_1tq, CAN_BS2_8tq, CAN_BS1_9tq, 4, CAN_Mode_Normal); //can初始化

    while (1)
    {
        static int m = 0;
        m++;
        can_printf("Hello, Have a Good Day, %d Seconds Have Passed Now!!!", m);
        delay_ms(1000);
    }

}

最后可以看一下现象,本人用Qt编写了一个简单的上位机程序,这里不过多赘述,主要就是将ASCII码转换成字符串,实现该功能的代码主要如下:

//vco是一个结构体数组,代表接收的CAN报文,.Data就是访问了其中的数据帧,
//将每次接收的CAN报文数据帧依次放到QByteArray中,然后转换成字符串
void MainWindow::displayText(VCI_CAN_OBJ *vco,DWORD dwRel)
{
    
    QByteArray data;
    for(int i = 0;i<dwRel;i++)
    {
        for(int j = 0;j<8;j++)
            data.append(vco[i].Data[j]);
    }

    QString str(data);
    ui->textEdit->append(str);
}

最后就是观察现象了,效果如下:

 最后,这是本人第一次发帖,如有什么不足之处请指出,还望大家多多包涵。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值