提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
由于考虑成本问题,使用AT32F421C8T7芯片,由芯片手册可知不含CAN的芯片资源,又考虑到LIN总线的通信速率不够快,想到了使用CAN的物理链路,串口通信,同样可以实现500K
提示:以下是本篇文章正文内容,下面案例可供参考
一、PPP协议是什么?
在PPP中:
开始和结束的flag byte都是0x7E,转义字节为0x7D,只要消息中出现标志或转义字节,它就会被0x7D转义,字节本身与0x20进行异或运算,例如0x7E变为0x7D 0x5E,0x7D变为0x7D 0x5D。Receiver取消转义转义字节并再次使用0x20对下一个字节进行异或,以获得原始数据。
二、使用步骤
1.主机发送部分
/**
* @brief 异或运算
* @param 无
* @retval 无
*/
u8 Xor_encryption(uint8_t data)
{
data^=0x20;
return data;
}
void Usart_SendByte(usart_type *TX_usart, uint8_t data)
{
usart_data_transmit(TX_usart,data);
//检测串口发送的数据
//若没有数据来 就会一直等待
while(usart_flag_get(TX_usart,USART_TDC_FLAG) == RESET);
}
void Usart_SendArray(usart_type *TX_usart, uint8_t *array, uint8_t num)
{
uint8_t i;
for(i=0; i<num; i++)
{
if((array[i]==0x11&&i>0)||(array[i]==0x99&&i<num-1)) //发送字节为开头字节(0x11)结尾字节(0x99)
{
Usart_SendByte(TX_usart,0x7D); //发送转义字节(0x7D)
Usart_SendByte(TX_usart,Xor_encryption(array[i])); //发送与0x20异或之后的数据
}else if(array[i]==0x7D) //发送字节为转义字节(0x7D)
{
Usart_SendByte(TX_usart,0x7D); //发送转义字符(0x7D)
Usart_SendByte(TX_usart,0x7D); //发送转义字符(0x7D)
}else
{
Usart_SendByte(TX_usart,array[i]); //发送正常数据
}
}
}
2.从机配置部分
void USART1_Config(void)//串口1配置
{
gpio_init_type gpio_init_struct;
gpio_default_para_init(&gpio_init_struct);
/* enable the usart1 and gpio clock */
crm_periph_clock_enable(CRM_USART1_PERIPH_CLOCK, TRUE);
crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
/* configure the usart1 tx pin */
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_pins = GPIO_PINS_6;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOB, &gpio_init_struct);
/* configure the usart1 rx pin */
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_pins = GPIO_PINS_7;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init(GPIOB, &gpio_init_struct);
/* configure usart1 param */
usart_init(USART1, 500000, USART_DATA_8BITS, USART_STOP_1_BIT);
usart_transmitter_enable(USART1, TRUE);//启动发送器
usart_receiver_enable(USART1, TRUE);//启动接接收器
nvic_irq_enable(USART1_IRQn, 1, 0); //配置串口优先级
usart_parity_selection_config(USART1, USART_PARITY_NONE);//无校验
usart_hardware_flow_control_set(USART1, USART_HARDWARE_FLOW_NONE);//无硬件流
usart_interrupt_enable(USART1, USART_RDBF_INT, TRUE); //Usart接收数据缓冲区满中断
usart_enable(USART1, TRUE);
}
3.从机接收部分
/**
* @brief 异或运算
* @param 无
* @retval 无
*/
u8 Xor_encryption(uint8_t data)
{
data^=0x20;
return data;
}
/**
* @brief this function handles usart1 handler.
* @param none
* @retval none
*/
u8 data;
u8 data_EN;
u8 data_ESC;
void USART1_IRQHandler(void)
{
Slave_RxMsg.Length=10; //定义串口接收数据长度
if(usart_interrupt_flag_get(USART1, USART_RDBF_FLAG) != RESET) //Usart接收数据缓冲区满标志
{
data=usart_data_receive(USART1); //接收数据
if(data==0x11) //判断是否为起始字节
{
Slave_RxMsg.Index=0; //接收字节索引清零开始接收有效数据
data_EN=1; //数据接收标志使能
Slave_RxMsg.Index++; //索引自增为1的有效数据
}
if(data_EN==1&&Slave_RxMsg.Index>0) //判断有效数据接收使能及有效数据索引
{
if(data==0x7D&&data_ESC==0) //判断数据是否为0X7D转义字符且转义字符标志为0
{
data_ESC=1; //第一次接收到转义字符,转义字符标志为1
}else if(data==0x7D&&data_ESC==1) //判断再次收到的数据是否为0X7D转义字符且转义字符标志为1
{
Slave_RxMsg.Data[Slave_RxMsg.Index]=data; //将转义字符填入有效数据数据
data_ESC=0; //转义字符标志为0
Slave_RxMsg.Index++; //有效字节索引加加
}else if(data!=0x7D&&data_ESC==1) //判断收到的数据是否为0X7D转义字符且转义字符标志为1
{
Slave_RxMsg.Data[Slave_RxMsg.Index]=Xor_encryption(data);//接收到的数据进行异或处理
data_ESC=0; //转义字符标志为0
Slave_RxMsg.Index++; //有效字节索引加加
}else if(data!=0x11&&data!=0x99&&data!=0x7D){//判断数据不为为起始字节,不为结束字节,不为转义字节
Slave_RxMsg.Data[Slave_RxMsg.Index]=data;//接收有效数据
Slave_RxMsg.Index++; //有效字节索引加加
}
if(data==0x99) //判断数据是否为结束字节
{
data_EN=0; //数据接收标志清0
Slave_RxMsg.Index=0; //有效字节索引清0
}
}
usart_flag_clear(USART1, USART_RDBF_FLAG); //清空Usart接收数据缓冲区满标志
}
}
总结
使用自定义协议,借助CAN的物理链路,传输速率提高了,虽然没有仲裁机制,但能满足传输需求,一发一收的形式