STM32f107 的 485通讯 源码 (串口1)

                                  STM32f107 的   485通讯   源码  (串口1)


实验目的:
学习串口的使用(接收与发送)

硬件资源:
1,LED0 (连接在PB8) 
2,串口1采用485通讯标准电路

实验现象:   
本实验,STM32串口1 通过485通讯    和上位机对话   ,    STM32接收上位机发过来的字符串, 01 03 00 00 00 05 85 C9
检测 5个通道的数据  ,通道包括 u16 R_m; u16 R_n;  u16 Rm[0]; u16 Rn[0] ..... u16 Rm[3]; u16 Rn[3].
最大检测 u16 Rm[32]; u16 Rn[32].

发送  01 03 0A 27 0F 27 0F 27 0F 27 0F 27 0F 27 0F 27 0F 27 0F 27 0F 27 0F A9 DC 
最大发送137个有效数据

注意事项:
1,电脑端串口调试助手波特率必须是9600. 数据为8位.停止位1位
2,请使用XCOM/SSCOM串口调试助手,其他串口助手可能控制DTR/RTS导致MCU复位/程序不运行
4,请用USB线连接在USB_232,找到USB转串口后测试本例程.



RE485.H 文件  源码:


extern u16 R_m; 
extern u16 Rm[32];
extern u16 R_n;
extern u16 Rn[32];

//模式控制
#define RS485_TX_EN PAout(12)//485模式控制.0,接收;1,发送.
//如果想串口中断接收,请不要注释以下宏定义
#define EN_USART1_RX 1//0,不接收;1,接收.

void RS485_Init(u32 bound);
void RS485_Send_Data(u8 *buf,u8 len);
void RS485_Receive_Data(u8 *buf,u8 *len);

#endif   




RE485.C 文件  源码:

#include "sys.h"    
#include "rs485.h"  
#include "delay.h"
#include "stm32f10x_usart.h"


#define  RS485_Addr    0x01    //  串口通讯地址


u8 RS485_TX_BUF[137];   //发送缓冲,最大137个字节.


 u16 R_m=0x270F;     //合母的      正对地电阻
 u16 Rm[32]={9999,9999,9999,9999,9999,9999,9999,9999,9999,9999,
           9999,9999,9999,9999,9999,9999,9999,9999,9999,9999,
         9999,9999,9999,9999,9999,9999,9999,9999,9999,9999,
              9999,9999, };    //支路的 正对地电阻
 u16 R_n=0x270F;       //合母的      负对地电阻
 u16 Rn[32]={9999,9999,9999,9999,9999,9999,9999,9999,9999,9999,
           9999,9999,9999,9999,9999,9999,9999,9999,9999,9999,
         9999,9999,9999,9999,9999,9999,9999,9999,9999,9999,
              9999,9999, };   //支路的 负对地电阻

/************************************************************************************


                         CRC   查阅表
 
*************************************************************************************/
/* CRC   高位字节表  */


u16 const auchCRCHi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x00,
} ;


/* Table of CRC values for low Corder byte */
u16 const auchCRCLo[] = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
0x40, 0x00,
};
/*****************************************************************************


                     CRC16   校验程序
                                        
*****************************************************************************/
 u16 GetCRC16(u8 *Sbuf, u8 usDataLen)
{
u16 uchCRCHi = 0xFFFF;                   // 高 CRC  字节初始化
u16 uchCRCLo = 0xFFFF;                  //   低 CRC  字节初始化
u16 uIndex;                              // CRC  循环中的索引
u16 Temp=0,Temp1=0; 

while(usDataLen--)                        //  消息传送缓冲区
{
Temp1 = Sbuf[Temp++] & 0x00ff;// 前  8 位 & 的结果是0 
uIndex = (uchCRCHi ^ Temp1) & 0x00ff; //   计算 CRC     异或  ^    二进制做加法
uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex];
uchCRCLo = auchCRCLo[uIndex];
}
uchCRCHi &= 0x00ff;
uchCRCLo &= 0x00ff;
return ((uchCRCLo << 8) | uchCRCHi);
}




/*****************************************************************************


      装载并计算 CRC,  以便串口发送 
数据 是 高位在前 低位在后     CRC 校验和 是 低位在前 高位在后 


*****************************************************************************/
void data_load(u8 t,u8 d,u8 n)    //  t 为通讯数据03   数据字节 : d 为起始字节  n为终止字节  
{
u8 k=0;
u16 TX_crc=0;


if((t==0x03)&&(n<34))                     
{
RS485_TX_BUF[0]=RS485_Addr;
   RS485_TX_BUF[1]=0x03;
RS485_TX_BUF[2]=2*n;    
 

for(k=0;k{
     RS485_TX_BUF[3]=(R_m>>8);
  RS485_TX_BUF[4]=(R_m &0x00ff);
  RS485_TX_BUF[5]=(R_n>>8);
  RS485_TX_BUF[6]=(R_n &0x00ff);
RS485_TX_BUF[(4*k)+7]=(Rm[d+k]>>8);
  RS485_TX_BUF[(4*k)+8]=(Rm[d+k]&0x00ff);   
RS485_TX_BUF[(4*k)+9]=(Rn[d+k]>>8);
  RS485_TX_BUF[(4*k)+10]=(Rn[d+k]&0x00ff);  
}
 TX_crc=GetCRC16(RS485_TX_BUF,((4*n)+3));                 
   RS485_TX_BUF[(4*n)+3]=( TX_crc & 0x00ff);              
  RS485_TX_BUF[(4*n)+4]=( TX_crc>>8);
}
}
/*****************************************************************************


串口1接收中断函数  


*****************************************************************************/

#ifdef EN_USART1_RX   //如果使能了接收

//接收缓存区
u8 RS485_RX_BUF[8];   //接收缓冲,最大8个字节.

u8 RS485_GetMobusOrderFlag;  //  串口接收指令操作数据是否有效标识符
 u8 RS485_GetDataCpye[8]; //接收缓冲,最大8个字节.  有效数组
//接收到的数据长度
u8 RS485_RX_CNT=0;    
  
void USART1_IRQHandler(void)     //串口1中断服务程序
{
u8 res,i;    
u8 k;
u16 IsCRC;
  u8 CRC_H,CRC_L;
 
  if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收到数据
{  
 
res =USART_ReceiveData(USART1); //读取接收到的数据
if(RS485_RX_CNT<8)
{
RS485_RX_BUF[RS485_RX_CNT]=res;//记录接收到的值
RS485_RX_CNT++;//接收数据增加1 
}
    if(RS485_RX_CNT==1)
    {
if(RS485_RX_BUF[0]!=RS485_Addr)
RS485_RX_CNT=0;
}
if(RS485_RX_CNT==2)
    {
if(RS485_RX_BUF[1]!=0x03)
RS485_RX_CNT=0;
}

if(RS485_RX_CNT==8)
    {
IsCRC=GetCRC16(RS485_RX_BUF,6);                       
CRC_H=IsCRC>>8;
    CRC_L=IsCRC&0x00ff;
if((CRC_L==RS485_RX_BUF[6])&&(CRC_H==RS485_RX_BUF[7]))  
{
for(i=0;i<8;i++)
   {
     RS485_GetDataCpye[i]=RS485_RX_BUF[i];
   }
      RS485_GetMobusOrderFlag=1;
}
else
 {
 RS485_RX_CNT=0;
   RS485_GetMobusOrderFlag=0;
  }
      RS485_TX_EN=1;                      
data_load(0X03,RS485_GetDataCpye[3],RS485_GetDataCpye[5]); 
RS485_Send_Data(RS485_TX_BUF,(RS485_GetDataCpye[5]*4)+5); 
RS485_TX_EN=0;  
for(k=0;k<8;k++)
      RS485_GetDataCpye[k]=0; 
}
}  

#endif  
//初始化IO 串口2
//pclk1:PCLK1时钟频率(Mhz)
//bound:波特率  
void RS485_Init(u32 bound)
{  
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
 
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);//使能USART1,GPIOA时钟

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;//PA12端口配置
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
 
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;//PA9
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽
  GPIO_Init(GPIOA, &GPIO_InitStructure);
   
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);  


RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1,ENABLE);//复位串口2
RCC_APB2PeriphResetCmd(RCC_APB2Periph_USART1,DISABLE);//停止复位
 

 #ifdef EN_USART1_RX  //如果使能了接收
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(USART1, &USART_InitStructure); ; //初始化串1
  
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //使能串口1中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级2级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //从优先级2级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
 
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
   
  USART_Cmd(USART1, ENABLE);                    //使能串口 
 
 #endif


  RS485_TX_EN=0; //默认为接收模式
}


//RS485发送len个字节.
//buf:发送区首地址
//len:发送的字节数
void RS485_Send_Data(u8 *buf,u8 len)
{
u8 t;
RS485_TX_EN=1;//设置为发送模式
  for(t=0;t//循环发送数据
{
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); 
USART_SendData(USART1,buf[t]);
}  
 
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
RS485_RX_CNT=0; 
RS485_TX_EN=0;//设置为接收模式
}




main 文件源码  :

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "rs485.h"
 


 int main(void)
 {
  u8 t=0;  
delay_init();      
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
LED_Init();    
RS485_Init(9600);
 
while(1)
{
// if(t==2)
// {
// R_m++;
// R_n++;
// }  
t++; 
delay_ms(200);
if(t==3)
{
LED0=!LED0;
}  
if(t==4)
{
t=0;
}  

}




             --------------- 以上代码经过测试,完全可用。

                                           在实际运用中需要考虑的是,485通讯接收过程中是否被   中断  如果中断,会产生通讯丢包的现象。














































你可能感兴趣的:(STM32)