stm32F103C8T6的can总线通信实验

本篇文章介绍一下stm32F103C8T6的can总线通信实验

需要两块stm32F103C8T6板子

can通信主要是用于两块板子之间的通信,简而言之就是用一块板子发指令,另一块板子接收指令并发出动作。之前搜索了好多例程,但是应用于stm32F103C8T6的例程很少,所以决定写一篇博客,也算是记录一下自己的学习过程。本人第一次写博客,如有错误,欢迎在评论区指出。话不多说,下面是我的发送端stm32的main.c的程序。

发送端的main.c

#include "stm32f10x.h"
#include "can.h"
#include "led.h"
#include "delay.h"
#include "oled.h"
#include "ds18b20.h"
int main(void)
{   
	u8 Buff[8];
	u8 ShowBuff[8];
	int Temp=0;
	int Count=0;
	SystemInit(); //设置系统时钟为72M
	LED_GPIO_Config();//LED管脚初始化
	CAN_GPIO_Config();//CAN管脚初始化
	CAN_NVIC_Configuration(); //CAN中断初始化   
	CAN_INIT();//CAN模块初始化	
	delay_init();
	DS18B20_Init();
	delay_ms(500);
	Temp=DS18B20_Get_Temp();
 	while(1)
   {
		  Temp=DS18B20_Get_Temp();
		  /*ShowBuff[0]='Y';
		    if(Temp>=0)
				 {
				   ShowBuff[1]='+';
				 }else
				 {
					  Temp=-Temp;					//数据转为正数
				    ShowBuff[1]='-';//变为负号
				 }
				 ShowBuff[2]=Temp/100+'0';
				 ShowBuff[3]=Temp%100/10+'0';
				 ShowBuff[4]='.';
				 ShowBuff[5]=Temp%100%10+'0';
			   ShowBuff[6]='L';*/			 
		 ShowBuff[0]='Y';
		 ShowBuff[1]='9';
		 ShowBuff[2]='7';
		 ShowBuff[3]='8';
		 ShowBuff[4]='6';
		 ShowBuff[5]='1';
		 ShowBuff[6]='L';
		 
		  Can_TxByte(ShowBuff,7);
		  LEDx=~LEDx;
			delay_ms(500);
			
  	}
}
  1. 定义一个ShowBuff数组 ,用来储存要发送的字节。例程本来是采用DS18B20做数据采集的传感器,这里为了测试是否可以通信,随意写了一段,发送“97861”,看看在另一块板子上是否可以显示;
  2. 用库函数**Can_TxByte(ShowBuff,7);**发送ShowBuff数组中的东西;

下面是can.c

定义了CAN_GPIO_Config();//CAN管脚初始化
CAN_NVIC_Configuration(); //CAN中断初始化
Can_TxByte(ShowBuff,7)几个库函数。

#include "can.h"
#include "led.h"
#include "stdio.h"

typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus;

/* 在中断处理函数中返回 */
__IO uint32_t ret = 0;

volatile TestStatus TestRx;	

/*CAN RX0 中断优先级配置  */
 void CAN_NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;

  	/* Configure the NVIC Preemption Priority Bits */  
  	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

	#ifdef  VECT_TAB_RAM  
	  /* Set the Vector Table base location at 0x20000000 */ 
	  NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); 
	#else  /* VECT_TAB_FLASH  */
	  /* Set the Vector Table base location at 0x08000000 */ 
	  NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
	#endif

	/* enabling interrupt */
  	NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN1_RX0_IRQn;;
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  	NVIC_Init(&NVIC_InitStructure);
}

/*CAN GPIO 和时钟配置 */
 void CAN_GPIO_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure; 
  /* 复用功能和GPIOB端口时钟使能*/	 
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE);	                        											 

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

  /* Configure CAN pin: RX */	 // PB8
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;	 // 上拉输入
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  
  /* Configure CAN pin: TX */   // PB9
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  
	//#define GPIO_Remap_CAN    GPIO_Remap1_CAN1 本实验没有用到重映射I/O
  GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
}

/*	CAN初始化 */
 void CAN_INIT(void)
{
  CAN_InitTypeDef        CAN_InitStructure;
  CAN_FilterInitTypeDef  CAN_FilterInitStructure;
  CanTxMsg TxMessage;  

  /* CAN register init */
  CAN_DeInit(CAN1);	//将外设CAN的全部寄存器重设为缺省值
  CAN_StructInit(&CAN_InitStructure);//把CAN_InitStruct中的每一个参数按缺省值填入

  /* CAN cell init */
  CAN_InitStructure.CAN_TTCM=DISABLE;//没有使能时间触发模式
  CAN_InitStructure.CAN_ABOM=DISABLE;//没有使能自动离线管理
  CAN_InitStructure.CAN_AWUM=DISABLE;//没有使能自动唤醒模式
  CAN_InitStructure.CAN_NART=DISABLE;//没有使能非自动重传模式
  CAN_InitStructure.CAN_RFLM=DISABLE;//没有使能接收FIFO锁定模式
  CAN_InitStructure.CAN_TXFP=DISABLE;//没有使能发送FIFO优先级
  CAN_InitStructure.CAN_Mode=CAN_Mode_Normal;//CAN设置为正常模式
  CAN_InitStructure.CAN_SJW=CAN_SJW_1tq; //重新同步跳跃宽度1个时间单位
  CAN_InitStructure.CAN_BS1=CAN_BS1_3tq; //时间段1为3个时间单位
  CAN_InitStructure.CAN_BS2=CAN_BS2_2tq; //时间段2为2个时间单位
  CAN_InitStructure.CAN_Prescaler=60;  //时间单位长度为60	
  CAN_Init(CAN1,&CAN_InitStructure);//波特率为:72M/2/60(1+3+2)=0.1 即100K

  /* CAN filter init */
  CAN_FilterInitStructure.CAN_FilterNumber=1;//指定过滤器为1
  CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;//指定过滤器为标识符屏蔽位模式
  CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;//过滤器位宽为32位
  CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;// 过滤器标识符的高16位值
  CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;//	 过滤器标识符的低16位值
  CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//过滤器屏蔽标识符的高16位值
  CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;//	过滤器屏蔽标识符的低16位值
  CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_FIFO0;// 设定了指向过滤器的FIFO为0
  CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;// 使能过滤器
  CAN_FilterInit(&CAN_FilterInitStructure);//	按上面的参数初始化过滤器

  /* CAN FIFO0 message pending interrupt enable */ 
 CAN_ITConfig(CAN1,CAN_IT_FMP0, ENABLE); //使能FIFO0消息挂号中断
 
 }  
/* 发送两个字节的数据*/
void can_tx(u8 Data1,u8 Data2)
{ 
  CanTxMsg TxMessage;  

  TxMessage.StdId=0x00;	//标准标识符为0x00
  TxMessage.ExtId=0x0000; //扩展标识符0x0000
  TxMessage.IDE=CAN_ID_EXT;//使用标准标识符
  TxMessage.RTR=CAN_RTR_DATA;//为数据帧
  TxMessage.DLC=2;	//	消息的数据长度为2个字节
  TxMessage.Data[0]=Data1; //第一个字节数据
  TxMessage.Data[1]=Data2; //第二个字节数据 
  CAN_Transmit(CAN1,&TxMessage); //发送数据
  
 
}

void Can_TxByte(u8 *Data,u8 len)
{ 
	int ix=0;
  CanTxMsg TxMessage;  

  TxMessage.StdId=0x00;	//标准标识符为0x00
  TxMessage.ExtId=0x0000; //扩展标识符0x0000
  TxMessage.IDE=CAN_ID_EXT;//使用标准标识符
  TxMessage.RTR=CAN_RTR_DATA;//为数据帧
  TxMessage.DLC=len;	//	消息的数据长度为2个字节
//  TxMessage.Data[0]=Data1; //第一个字节数据
//  TxMessage.Data[1]=Data2; //第二个字节数据 
	for(ix=0;ix<len;ix++)
	TxMessage.Data[ix]=Data[ix];
  CAN_Transmit(CAN1,&TxMessage); //发送数据
  
 
}

/* USB中断和CAN接收中断服务程序,USB跟CAN公用I/O,这里只用到CAN的中断。 */
void USB_LP_CAN1_RX0_IRQHandler(void)
{
  int ix=0;
  CanRxMsg RxMessage;

  RxMessage.StdId=0x00;
  RxMessage.ExtId=0x00;
  RxMessage.IDE=0;
  RxMessage.DLC=0;
  RxMessage.FMI=0;
	
  RxMessage.Data[0]=0x00;
  RxMessage.Data[1]=0x00;    
  for(ix=0;ix<8;ix++)
	 RxMessage.Data[ix]=0;			  
  CAN_Receive(CAN1,CAN_FIFO0, &RxMessage); //接收FIFO0中的数据  
 
  if((RxMessage.Data[0]==0x99)&&(RxMessage.Data[1]==0xbb))   
  { LED1(0);LED2(1);}
   if((RxMessage.Data[0]==0x55)&&(RxMessage.Data[1]==0x77))   
  { LED1(1);LED2(0);}
   
  
} 

显示屏端的main.c

#include "stm32f10x.h"
#include "can.h"
#include "led.h"
#include "delay.h"
#include "oled.h"
#include "stdio.h"

void Show_log(void)
{

    OLED_ShowCHinese(27,2,0);
		OLED_ShowCHinese(45,2,1);
		OLED_ShowCHinese(63,2,2);
	  OLED_ShowCHinese(81,2,3);//显示"当前温度"几个字
	  OLED_ShowCHinese(81,4,5);//显示 ℃
	 
}

int main(void)
{   
	int Tmep=0;
	
	char ShowBuff[8]={0};
	SystemInit(); //设置系统时钟为72M
  LED_GPIO_Config();//LED管脚初始化
	CAN_GPIO_Config();//CAN管脚初始化
	CAN_NVIC_Configuration(); //CAN中断初始化   
	CAN_INIT();//CAN模块初始化	
	delay_init();
	OLED_Init();
	OLED_Clear();
	Show_log();
 	while(1)
   {
		 
	 
		 if(Can_RxBuff[0]=='Y'&&Can_RxBuff[6]=='L')//接收到有效数据 
		 {
				 ShowBuff[0]=Can_RxBuff[1];//提取有效数据 
			   ShowBuff[1]=Can_RxBuff[2];
			   ShowBuff[2]=Can_RxBuff[3];
			   ShowBuff[3]=Can_RxBuff[4];
			   ShowBuff[4]=Can_RxBuff[5];
			 
				 OLED_ShowString(36,4,(u8*)ShowBuff,16);//显示当前值 
			   Can_RxBuff[0]=0;
			   Can_RxBuff[6]=0;
		 }
		 
		 SystemInit();	// 配置系统时钟为72M 	
 LED_GPIO_Config(); //LED 端口初始化 

  
		
		LED1( OFF );			  // 亮
		delay_ms(5000);
		LED1( ON );		  // 灭

  
  	}
}
  1. 显示屏端STM32板子采用ShowBuff做临时数组,当Can_RxBuff[]中接收到以"Y"开头"L"结尾的数据时,认为是有效数据,并放入临时数组ShowBuff中;
    4.用函数OLED_ShowString(36,4,(u8*)ShowBuff,16);将值显示在显示屏端STM32的显示屏上。
  • 29
    点赞
  • 183
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 20
    评论
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九棵树

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值