1 常用RS485
通常使用RS485是在串口的基础之上,外加485芯片,如下图所示。
2 RS485传送数据限制在8位的原因
实验室里有个项目,需要在两个单片机之间进行485通信传送数据,在淘宝买了两个485模块想通过485模块发送数据,发现直接通过串口转换的数据长度最大只是255,查看代码后发现,串口的配置代码中数据长度是8位,代码如下所示。
USART_InitStructure.USART_BaudRate = bound;//波特率设置
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位数据长度
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_Rx | USART_Mode_Tx;//收发模式
USART_Init(USART3, &USART_InitStructure); ; //初始化串口
3 发送功能实现
我参考的程序是正点原子的程序,发送功能如下所示:
//RS485发送len个字节.
//buf:发送区首地址
//len:发送的字节数(为了和本代码的接收匹配,这里建议不要超过64个字节)
void RS485_Send_Data(u8 *buf,u8 len)
{
u8 t;
for(t=0;t<len;t++) //循环发送数据
{
while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
USART_SendData(USART3,buf[t]);
}
while(USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
RS485_RX_CNT=0;
}
代码可以实现发送len个长度的uint8_t类型的数据。
经过改良,我可以一次发送两个8位数据,如下所示:
uint16_t Tx=55555;
uint8_t TxData[2];
//将Txz转换成两个8位数据进行传送
TxData[0] = (Tx[0]&0xFF00)>>8;
TxData[1] = (Tx[0]&0x00FF);
在通过RS485_Send_Data(TxData,2)即可发送两个8位数据。
封装过如下代码所示:
//一次发送10个16位的数据
void get_val(uint16_t ch[10],uint8_t T_D[20])
{
//第一个数
T_D[0] = (ch[0]&0xFF00)>>8;
T_D[1] = (ch[0]&0x00FF);
//第二个数
T_D[2] = (ch[1]&0xFF00)>>8;
T_D[3] = (ch[1]&0x00FF);
//第三个数
T_D[4] = (ch[2]&0xFF00)>>8;
T_D[5] = (ch[2]&0x00FF);
//第四个数
T_D[6] = (ch[3]&0xFF00)>>8;
T_D[7] = (ch[3]&0x00FF);
//第五个数
T_D[8] = (ch[4]&0xFF00)>>8;
T_D[9] = (ch[4]&0x00FF);
//第6个数
T_D[10] = (ch[5]&0xFF00)>>8;
T_D[11] = (ch[5]&0x00FF);
//第7个数
T_D[12] = (ch[6]&0xFF00)>>8;
T_D[13] = (ch[6]&0x00FF);
//第8个数
T_D[14] = (ch[7]&0xFF00)>>8;
T_D[15] = (ch[7]&0x00FF);
//第9个数
T_D[16] = (ch[8]&0xFF00)>>8;
T_D[17] = (ch[8]&0x00FF);
//第10个数
T_D[18] = (ch[9]&0xFF00)>>8;
T_D[19] = (ch[9]&0x00FF);
}
经过改进后代码如下:
void get_valx(uint16_t ch[10],uint8_t T_D[20])
{
static int i=0;
for(int k=0;k<10;k++)
{
T_D[i] = (ch[k]&0xFF00)>>8;
T_D[i+1] = (ch[k]&0x00FF);
i+=2;
}
}
4 接收功能实现
接收数据的功能是正点原子代码经过改良,可一次接收64个uint8_t类型的数据,长度可自行更改。
//接收缓存区
u8 RS485_RX_BUF[64]; //接收缓冲,最大64个字节.
//接收到的数据长度
u8 RS485_RX_CNT=0;
void USART3_IRQHandler(void)
{
u8 res;
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) //接收到数据
{
res =USART_ReceiveData(USART3); //读取接收到的数据
if(RS485_RX_CNT<64)
{
RS485_RX_BUF[RS485_RX_CNT]=res; //记录接收到的值
RS485_RX_CNT++; //接收数据增加1
}
}
}
//RS485查询接收到的数据
//buf:接收缓存首地址
//len:读到的数据长度
void RS485_Receive_Data(u8 *buf,u8 *len)
{
u8 rxlen=RS485_RX_CNT;
u8 i=0;
*len=0; //默认为0
delay_ms(10); //等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束
if(rxlen==RS485_RX_CNT&&rxlen)//接收到了数据,且接收完成了
{
for(i=0;i<rxlen;i++)
{
buf[i]=RS485_RX_BUF[i];
}
*len=RS485_RX_CNT; //记录本次数据长度
RS485_RX_CNT=0; //清零
}
}
接收也可以一次接收两个8位数据长度,并进行整合。
uint8_t rx[2];
uint16_t ch;
ch=((rx[0]&0x00FF)<<8)|(rx[1]&0xFF);
经过转换即将两个数据整合到一起,一次接收10个16位的数据,具体实现如下所示。
void Receive_Val(uint16_t ch[10],uint8_t rx[20])
{
ch[0]=((rx[0]&0x00FF)<<8)|(rx[1]&0xFF);
ch[1]=((rx[2]&0x00FF)<<8)|(rx[3]&0xFF);
ch[2]=((rx[4]&0x00FF)<<8)|(rx[5]&0xFF);
ch[3]=((rx[6]&0x00FF)<<8)|(rx[7]&0xFF);
ch[4]=((rx[8]&0x00FF)<<8)|(rx[9]&0xFF);
ch[5]=((rx[10]&0x00FF)<<8)|(rx[11]&0xFF);
ch[6]=((rx[12]&0x00FF)<<8)|(rx[13]&0xFF);
ch[7]=((rx[14]&0x00FF)<<8)|(rx[15]&0xFF);
ch[8]=((rx[16]&0x00FF)<<8)|(rx[17]&0xFF);
ch[9]=((rx[18]&0x00FF)<<8)|(rx[19]&0xFF);
}
经过改良如下所示:
void Receive_Valx(uint16_t ch[10],uint8_t rx[20])
{
static int i=0;
for(int j=0;j<10;j++)
{
ch[j]=((rx[i]&0x00FF)<<8)|(rx[i+1]&0xFF);
i+=2;
}
}
经过整理,便可以将两端数据进行整合,发送和接收便都可以以16位数据进行计算了。