485、CAN通讯、LCD段码屏 电动车仪表测试盒

一.MCU

     此项目MCU使用的是芯圣的一款32位单片机,内部自带CAN外设。

     项目需要实现的功能是:通过诸多外部按键,LCD屏会显示测试内容,例如速度 、档位、故障码,同时通过数据发送端口(485或CAN)发送相应数据到电动车仪表,实现测试功能。

LCD段码屏的驱动我之前有过说明,具体参考LCD段码式液晶屏驱动-CSDN博客

二.485通讯

    485通讯说白了就是串口通信,区别在于串口极其容易受干扰且传输距离近,MCU出来的TX,RX经过485芯片强化升级后变为抗干扰能力强的差分信号。

  区别就在于串口是全双工的,可以同时收发,而485是半双工的,同一时间只能收或者发。当然氪金大佬可以选择全双工的485芯片,也可以通过增加个自动收发电路来实现。但是那个电路我没有实际使用过,我的老大说可以用,那就应该没问题。可以参考这位大佬的博客:终于讲透了,史上最详细的RS485自动收发电路你一定要掌握-CSDN博客

接下来我们看个常用的:

  硬件连接,485RX、TX接MCU串口TX、RX   485EN接任意IO口,用来切换485收发模式

软件部分    CAN收发:

void RS485_Config()  //注意手动切换485收发模式
{
	  GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
	
	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

	 	//USART2 TX as PA2
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);                        
	
    //USART2 Rx as PA3
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);	
	
	  //485控制管脚
	  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);	
		
    USART_InitStructure.USART_BaudRate = 9600;//波特率9600
    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_Tx |USART_Mode_Rx;
    USART_Init(USART2, &USART_InitStructure);
	  USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断
//	  USART_ITConfig(USART2, USART_IT_TXE, ENABLE); //开启串口发送中断
	  USART_Cmd(USART2, ENABLE);
		//控制485芯片进入接收模式
    GPIO_ResetBits(GPIOA,GPIO_Pin_4);
}

void RS485_Send_Data(u8 *buf,u8 len) //发送函数,注意发送完改为接收
{
     u8 t;
     GPIO_SetBits(GPIOA,GPIO_Pin_4);//设置为发送模式
     for(t=0;t<len;t++)
     {
         while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);//等待发送完成
         USART_SendData(USART2,buf[t]);
     }     
		 while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET)
		 ;
     USART2_RX_Data_Len=0;
     GPIO_ResetBits(GPIOA,GPIO_Pin_4);//设置为接收模式    
}

void USART2_IRQHandler(void)//中断接收
{
	u8 res;
	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收到数据
  {
		res =USART_ReceiveData(USART2); //读取接收到的数据
		if(USART2_RX_Data_Len<USART2_RX_LEN)
		{
			USART2_RX_Buf[USART2_RX_Data_Len]=res; //记录接收到的值
			USART2_RX_Data_Len++; //接收数据增加 1
		}
		USART2_RX_Flag=1;
	}
	
}

三.CAN通讯

   CAN通讯我只在车子的仪表上用过,当时速率是500K或者是250K。

硬件连接:

     R32更具实际情况接,我是用了120欧,目的为了让总线寄生电容快速放电,确保总线快速进入隐性状态。

   软件代码:

  

void CAN_Configuration(void)
{
  CAN_InitTypeDef        CAN_InitStructure;
  CAN_FilterInitTypeDef  CAN_FilterInitStructure;
  /* CAN register init */
  CAN_DeInit(CAN1);
  CAN_StructInit(&CAN_InitStructure);
	CAN_InitStructure.CAN_Mode =CAN_Mode_Normal;  //工作模式(正常、静默、环回和环回静默)
	CAN_InitStructure.CAN_Prescaler =9;	          //500K
	CAN_InitStructure.CAN_BS1=CAN_BS1_5tq;		    //BTR-TS1 时间段1 占用了5个时间单元 
	CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;		    //BTR-TS2 时间段2 占用了2个时间单元	  
	CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;		    //BTR-SJW 重新同步跳跃宽度 2个时间单元
	
	CAN_InitStructure.CAN_NART=DISABLE;			      //自动重传	 DISABLE-自动重传  ENABLE-不自动重传
	CAN_InitStructure.CAN_TXFP=ENABLE;			      //发送邮箱优先级  ENABLE-先请求先发送    DISABLE-ID号小的先发送
	CAN_InitStructure.CAN_RFLM=DISABLE;			      //报文锁定   ENABLE-FIFO溢出,新报文丢弃   DISABLE-新报文覆盖老报文
  CAN_InitStructure.CAN_AWUM=ENABLE;			      //自动唤醒   ENABLE-自动唤醒    DISABLE-手动唤醒
	CAN_InitStructure.CAN_TTCM=DISABLE;			      //时间触发通信模式 ENABLE-开启  DISABLE-关闭
	CAN_InitStructure.CAN_ABOM=DISABLE;			      //离线自动恢复 ENABLE-自动恢复  DISABLE-手动恢复
	CAN_Init(CAN1, &CAN_InitStructure);

	//CAN过滤器初始化0
	CAN_FilterInitStructure.CAN_FilterNumber=0;						              //过滤器0
	CAN_FilterInitStructure.CAN_FilterIdHigh= 0x101<<5;		              //要筛选的ID高位 
	CAN_FilterInitStructure.CAN_FilterIdLow= 0;                         //要筛选的ID低位 
	CAN_FilterInitStructure.CAN_FilterMaskIdHigh= 0xFFFF;			          //筛选器高16位每位必须匹配
	CAN_FilterInitStructure.CAN_FilterMaskIdLow= 0;			                //筛选器低16位每位必须匹配
	CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;	    //选择过滤器位宽
	CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;	      //过滤器模式  屏蔽模式
	CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;  //配置过滤器关联 FIFO0和FIFO1
	CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;			          //过滤器开关
	CAN_FilterInit(&CAN_FilterInitStructure);
	CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);                            //FIF0消息挂号中断允许	
}

void CAN_Send()
{
   if(CANTX_100ms_F)  CANTX_State=1;
	if(CANTX_250ms_F)  CANTX_State=2;
	if(CANTX_500ms_F)  CANTX_State=3;
	if(CANTX_1000ms_F) CANTX_State=4;
	if(CanTx_Idle==0)return; //处于发送状态,返回
	
	if(CANTX_100ms_F||CANTX_250ms_F||CANTX_500ms_F||CANTX_1000ms_F)
	{
		switch(CANTX_State)
		{
			case 1:
			{
				TX_100ms_Cnt++;
				if(TX_100ms_Cnt==1)
				{
         CAN_SetMsg(&TxMessage,0x18203120,Data_ID_18203120);
				break;
				}      				
				if(TX_100ms_Cnt==2)
				{
         CAN_SetMsg(&TxMessage,0x18300A30,Data_ID_18300A30);
				 TX_100ms_Cnt=0;
				 CANTX_100ms_F=0;	
				break;
				}			
			}
			break;			
			case 2:
			{
				TX_250ms_Cnt++;
				if(TX_250ms_Cnt==1)
				{
         CAN_SetMsg(&TxMessage,0x18200A20,Data_ID_18200A20);
					break;
				}
        
				if(TX_250ms_Cnt==2)
				{
         CAN_SetMsg(&TxMessage,0x18202A20,Data_ID_18202A20);
					break;
				}
        
				if(TX_250ms_Cnt==3)
				{
         CAN_SetMsg(&TxMessage,0x18202B20,Data_ID_18202B20);
					break;
				}
        
				if(TX_250ms_Cnt==4)
				{
         CAN_SetMsg(&TxMessage,0x18203220,Data_ID_18203220);
					break;
				}       
				if(TX_250ms_Cnt==5)
				{
         CAN_SetMsg(&TxMessage,0x18300630,Data_ID_18300630);
					 break;
				}      
				if(TX_250ms_Cnt==6)
				{
         CAN_SetMsg(&TxMessage,0x18300830,Data_ID_18300830);
					 break;
				}      
				if(TX_250ms_Cnt==7)
				{
         CAN_SetMsg(&TxMessage,0x18300930,Data_ID_18300930);
					break;
				}       
				if(TX_250ms_Cnt==8)
				{
         CAN_SetMsg(&TxMessage,0x18300B30,Data_ID_18300B30);
					break;
				}     
				if(TX_250ms_Cnt==9)
				{
         CAN_SetMsg(&TxMessage,0x18300C30,Data_ID_18300C30);
					break;
				}      
				if(TX_250ms_Cnt==10)
				{
         CAN_SetMsg(&TxMessage,0x18200A21,Data_ID_18200A21);
					break;
				}       
				if(TX_250ms_Cnt==11)
				{
         CAN_SetMsg(&TxMessage,0x18202A21,Data_ID_18202A21);
					break;
				}        
				if(TX_250ms_Cnt==12)
				{
         CAN_SetMsg(&TxMessage,0x18202B21,Data_ID_18202B21);
				break;
				}       
				if(TX_250ms_Cnt==13)
				{
         CAN_SetMsg(&TxMessage,0x18100710,Data_ID_18100710);
				 break;
				}	
				if(TX_250ms_Cnt==14)
				{
         CAN_SetMsg(&TxMessage,0x18202920,Data_ID_18202920);
				 break;
				}
				if(TX_250ms_Cnt==15)
				{
         CAN_SetMsg(&TxMessage,0x18202921,Data_ID_18202921);
				 break;
				}
				if(TX_250ms_Cnt==16)
				{
         CAN_SetMsg(&TxMessage,0x18203820,Data_ID_18203820);
				 TX_250ms_Cnt=0;
				 CANTX_250ms_F=0;
				 break;
				}
			}
			break;
			case 3:
			{
				TX_500ms_Cnt++;
				if(TX_500ms_Cnt==1)
				{
         CAN_SetMsg(&TxMessage,0x18300E3F,Data_ID_18300E3F);
				 break;
				}
        
				
				if(TX_500ms_Cnt==2)
				{
         CAN_SetMsg(&TxMessage,0x18100C10,Data_ID_18100C10);
				 TX_500ms_Cnt=0;
				 CANTX_500ms_F=0;		
				 break;
				}
        
			}
			break;
			
			case 4:
			{
         CAN_SetMsg(&TxMessage,0x18500550,Data_ID_18500550);
				 CANTX_1000ms_F=0;
			}
      break;
			default:
				break;		
	   }			
				
	 	CAN_Transmit(CAN1, &TxMessage);
		CAN_ITConfig(CAN1,CAN_IT_TME, ENABLE); //开传输邮箱空中断,传输邮箱空则代表数据传输完毕
		CanTx_Idle=0;	


}

void USB_HP_CAN1_TX_IRQHandler(void)//数据传输完毕进入到这个中断来
{
	CAN_ClearITPendingBit(CAN1, CAN_IT_TME);//清除中断挂起标志位
	CanTx_Idle=0xff;//发送处于空闲状态,表示可以再次发送
}


void CAN_SetMsg(CanTxMsg *TxMessage,uint32_t ExtId_Data,uint8_t *TxData)//扩展帧,数据
{	  
	uint8_t ubCounter = 0;

  TxMessage->ExtId =ExtId_Data;          //需要发送的扩展ID号     
  TxMessage->IDE=CAN_ID_EXT;				     //扩展帧	 
  TxMessage->RTR=CAN_RTR_DATA;				   //数据帧
  TxMessage->DLC=8;							 
	for (ubCounter = 0; ubCounter < 8; ubCounter++)
  {
    TxMessage->Data[ubCounter] = *(TxData+ubCounter);
  }
}


void USB_LP_CAN1_RX0_IRQHandler(void) //CAN接收中断
{
//	/*从邮箱中读出报文*/
//	CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);
//	if((RxMessage.IDE==CAN_ID_EXT)&&(RxMessage.DLC==8))
//	{
//		canRxDataBuf.can_msg_id=RxMessage.ExtId;
//		memcpy(canRxDataBuf.can_msg_data,RxMessage.Data,8);
//	}
}

 此项目的DC-DC 以及LDO电路这里不做描述,后续会单独起个电源电路的记录。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值