stm32之RS485

stm32的rs485和rs232都是用到串口通信USART,寄存器的配置几乎一样,rs485用USART2,前面博客已经讲了如何配置串口,以及rs485协议,在这里就不再多提。下面直接讲如何设置,开发板的电路如下:


本模块使用的是SP3490芯片是一种485全双工收发芯片。
下面讲一下程序设计要点:
1.配置RCC寄存器组,使用PLL输出72MHz时钟并作为主时钟源。

2.配置GPIOA端口,分别设置PA2为能推挽输出,PA3为浮空输入模式

3.配置USART设备,主要参数为:使用115200bps波特率、8位数据长度、1个停止位且无校验位、全双工模式。

下面直接上程序,分别用polling法和中断法。

polling:

#include "stm32f10x.h"
#include "stdio.h"
#include "stdarg.h"

void RCC_Configuration(void);
void GPIO_Configuration(void);
void USART_Configuration(void);
int fputc(int ch, FILE *f);
void USART_OUT(USART_TypeDef* USARTx, uint8_t *Data,...);
char *itoa(int value, char *string, int radix);

int main()
{
		u16 i = 0;
		RCC_Configuration();
		GPIO_Configuration();
		USART_Configuration();
		
		printf("\r\nWelcome!\r\n");
		printf("\r\n你好,严世富\r\n");
		USART_OUT(USART2,"\r 好好学习,天天向上!\n");
		while(1)
		{
				if(USART_GetFlagStatus(USART2 , USART_FLAG_RXNE) == SET)//判断接收数据寄存器非空标准位是否为1
				{	
						USART_SendData(USART2,USART_ReceiveData(USART2));//向usart2发送从usart2接收的数据
						for(i = 0; i < 500; i++);                        //短暂延时减少出错
				}
		}
	
}
/*格式化串口输出函数*/
void USART_OUT(USART_TypeDef* USARTx, uint8_t *Data,...){ 
	const char *s;
    int d;
    char buf[16];
    va_list ap;
    va_start(ap, Data);

	while(*Data!=0){				                          //判断是否到达字符串结束符
		if(*Data==0x5c){									  //'\'
			switch (*++Data){
				case 'r':							          //回车符
					USART_SendData(USARTx, 0x0d);	   

					Data++;
					break;
				case 'n':							          //换行符
					USART_SendData(USARTx, 0x0a);	
					Data++;
					break;
				
				default:
					Data++;
				    break;
			}
			
			 
		}
		else if(*Data=='%'){									  //
			switch (*++Data){				
				case 's':										  //字符串
                	s = va_arg(ap, const char *);
                	for ( ; *s; s++) {
                    	USART_SendData(USARTx,*s);
						while(USART_GetFlagStatus(USARTx, USART_FLAG_TC)==RESET);
                	}
					Data++;
                	break;
            	case 'd':										  //十进制
                	d = va_arg(ap, int);
                	itoa(d, buf, 10);
                	for (s = buf; *s; s++) {
                    	USART_SendData(USARTx,*s);
						while(USART_GetFlagStatus(USARTx, USART_FLAG_TC)==RESET);
                	}
					Data++;
                	break;
				default:
					Data++;
				    break;
			}		 
		}
		else USART_SendData(USARTx, *Data++);
		while(USART_GetFlagStatus(USARTx, USART_FLAG_TC)==RESET);
	}
}

/*整型数据转换为字符串函数*/
char *itoa(int value, char *string, int radix)
{
    int     i, d;
    int     flag = 0;
    char    *ptr = string;

    /* This implementation only works for decimal numbers. */
    if (radix != 10)
    {
        *ptr = 0;
        return string;
    }

    if (!value)
    {
        *ptr++ = 0x30;
        *ptr = 0;
        return string;
    }

    /* if this is a negative value insert the minus sign. */
    if (value < 0)
    {
        *ptr++ = '-';

        /* Make the value positive. */
        value *= -1;
    }

    for (i = 10000; i > 0; i /= 10)
    {
        d = value / i;

        if (d || flag)
        {
            *ptr++ = (char)(d + 0x30);
            value -= (d * i);
            flag = 1;
        }
    }

    /* Null terminate the string. */
    *ptr = 0;

    return string;

} /* NCL_Itoa */

/*时钟设置*/
void RCC_Configuration(void)
{
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
		RCC_APB1PeriphClockCmd( RCC_APB1Periph_USART2, ENABLE);  
}

/*GPIO口配置*/
void GPIO_Configuration(void)
{
		GPIO_InitTypeDef GPIO_InitStructure;
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;//USART1 TX
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
		GPIO_Init(GPIOA, &GPIO_InitStructure);
	
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;	//USART1 RX
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//复用浮空输入
		GPIO_Init(GPIOA, &GPIO_InitStructure);
		
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;	         		 //USART2 TX
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    		 //复用推挽输出
		GPIO_Init(GPIOA, &GPIO_InitStructure);		    		 //A端口 

		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;	         	 	 //USART2 RX
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   	 //复用开漏输入
		GPIO_Init(GPIOA, &GPIO_InitStructure);
}

/*配置串口*/
void USART_Configuration(void)
{
		USART_InitTypeDef USART_InitStructure;
	
		USART_InitStructure.USART_BaudRate = 115200;//波特率是115200
		USART_InitStructure.USART_WordLength = USART_WordLength_8b;//数据位为8位
		USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位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);
		USART_Init(USART2, &USART_InitStructure);
	
		USART_Cmd(USART1 , ENABLE);
		USART_Cmd(USART2 , ENABLE); /* Enable the USARTx */
}
/*printf函数输出重定向 输出到USART2*/
int fputc(int ch,FILE *f)
{
		USART_SendData(USART2,(u8) ch);
		while(USART_GetFlagStatus(USART2,USART_FLAG_TC) == RESET);
		return ch;
}

interrupt:

main.c

#include "stm32f10x.h"
#include "stdio.h"
#include "stdarg.h"

uint8_t TxBuffer1[] = "USART Interrupt Example: This is USART2 DEMO";  
uint8_t RxBuffer1[],rec_f,tx_flag;
__IO uint8_t TxCounter1 = 0x00;
__IO uint8_t RxCounter1 = 0x00; 

void RCC_Configuration(void);
void GPIO_Configuration(void);
void USART_Configuration(void);
void NVIC_Configuration(void);
int fputc(int ch, FILE *f);
void USART_OUT(USART_TypeDef* USARTx, uint8_t *Data,...);
char *itoa(int value, char *string, int radix);

int main()
{

		RCC_Configuration();
		GPIO_Configuration();
		USART_Configuration();
		NVIC_Configuration();
	
		printf("\r\nWelcome!\r\n");
		printf("\r\n你好,严世富\r\n");
		USART_OUT(USART2,"\r 好好学习,天天向上!\n");
		while(1)
		{
				if(rec_f==1)
					{												  //判断是否收到一帧有效数据
							rec_f=0;
							USART_OUT(USART2,"\r\n您发送的信息为: \r\n");    
							USART_OUT(USART2,&TxBuffer1[0]);
					}
		}
	
}
/*格式化串口输出函数*/
void USART_OUT(USART_TypeDef* USARTx, uint8_t *Data,...){ 
	const char *s;
    int d;
    char buf[16];
    va_list ap;
    va_start(ap, Data);

	while(*Data!=0){				                          //判断是否到达字符串结束符
		if(*Data==0x5c){									  //'\'
			switch (*++Data){
				case 'r':							          //回车符
					USART_SendData(USARTx, 0x0d);	   

					Data++;
					break;
				case 'n':							          //换行符
					USART_SendData(USARTx, 0x0a);	
					Data++;
					break;
				
				default:
					Data++;
				    break;
			}
			
			 
		}
		else if(*Data=='%'){									  //
			switch (*++Data){				
				case 's':										  //字符串
                	s = va_arg(ap, const char *);
                	for ( ; *s; s++) {
                    	USART_SendData(USARTx,*s);
						while(USART_GetFlagStatus(USARTx, USART_FLAG_TC)==RESET);
                	}
					Data++;
                	break;
            	case 'd':										  //十进制
                	d = va_arg(ap, int);
                	itoa(d, buf, 10);
                	for (s = buf; *s; s++) {
                    	USART_SendData(USARTx,*s);
						while(USART_GetFlagStatus(USARTx, USART_FLAG_TC)==RESET);
                	}
					Data++;
                	break;
				default:
					Data++;
				    break;
			}		 
		}
		else USART_SendData(USARTx, *Data++);
		while(USART_GetFlagStatus(USARTx, USART_FLAG_TC)==RESET);
	}
}

/*整型数据转换为字符串函数*/
char *itoa(int value, char *string, int radix)
{
    int     i, d;
    int     flag = 0;
    char    *ptr = string;

    /* This implementation only works for decimal numbers. */
    if (radix != 10)
    {
        *ptr = 0;
        return string;
    }

    if (!value)
    {
        *ptr++ = 0x30;
        *ptr = 0;
        return string;
    }

    /* if this is a negative value insert the minus sign. */
    if (value < 0)
    {
        *ptr++ = '-';

        /* Make the value positive. */
        value *= -1;
    }

    for (i = 10000; i > 0; i /= 10)
    {
        d = value / i;

        if (d || flag)
        {
            *ptr++ = (char)(d + 0x30);
            value -= (d * i);
            flag = 1;
        }
    }

    /* Null terminate the string. */
    *ptr = 0;

    return string;

} /* NCL_Itoa */

/*时钟设置*/
void RCC_Configuration(void)
{
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
		RCC_APB1PeriphClockCmd( RCC_APB1Periph_USART2, ENABLE);  
}

/*GPIO口配置*/
void GPIO_Configuration(void)
{
		GPIO_InitTypeDef GPIO_InitStructure;
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;//USART1 TX
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
		GPIO_Init(GPIOA, &GPIO_InitStructure);
	
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;	//USART1 RX
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//复用浮空输入
		GPIO_Init(GPIOA, &GPIO_InitStructure);
		
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;	         		 //USART2 TX
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    		 //复用推挽输出
		GPIO_Init(GPIOA, &GPIO_InitStructure);		    		 //A端口 

		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;	         	 	 //USART2 RX
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   	 //复用开漏输入
		GPIO_Init(GPIOA, &GPIO_InitStructure);
}

/*配置串口*/
void USART_Configuration(void)
{
		USART_InitTypeDef USART_InitStructure;
	
		USART_InitStructure.USART_BaudRate = 115200;//波特率是115200
		USART_InitStructure.USART_WordLength = USART_WordLength_8b;//数据位为8位
		USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位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);
		USART_Init(USART2, &USART_InitStructure);
	
		USART_Cmd(USART1 , ENABLE);
		USART_Cmd(USART2 , ENABLE); /* Enable the USARTx */
}
/*printf函数输出重定向 输出到USART2*/
int fputc(int ch,FILE *f)
{
		USART_SendData(USART2,(u8) ch);
		while(USART_GetFlagStatus(USART2,USART_FLAG_TC) == RESET);
		return ch;
}
/*配置中断控制器*/
void NVIC_Configuration(void)
{
  /*  结构声明*/
  NVIC_InitTypeDef NVIC_InitStructure;

		     
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);	    

  NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;			     	//设置串口1中断
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	     	//抢占优先级 0
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;				//子优先级为0
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;					//使能
  NVIC_Init(&NVIC_InitStructure);
}

stm32fl0x_it.c

#include "stm32f10x_it.h"

extern uint8_t TxBuffer1[]; 
extern uint8_t RxBuffer1[];
extern __IO uint8_t RxCounter1; 

extern uint8_t rec_f,tx_flag;
void USART2_IRQHandler(void)      //串口1 中断服务程序
{
  unsigned int i;
  if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)	   //判断读寄存器是否非空
  {	
    
    RxBuffer1[RxCounter1++] = USART_ReceiveData(USART2);   //将读寄存器的数据缓存到接收缓冲区里
	
    if(RxBuffer1[RxCounter1-2]=='o'&&RxBuffer1[RxCounter1-1]=='k')     //判断结束标志是否是ok
    {
	  for(i=0; i< RxCounter1-2; i++) TxBuffer1[i]	= RxBuffer1[i]; 	     //将接收缓冲器的数据转到发送缓冲区,准备转发
	  rec_f=1;															 //接收成功标志
	  TxBuffer1[RxCounter1-2]=0;		                                     //发送缓冲区结束符    
	  RxCounter1=0;
	  
    }
  }
  
  if(USART_GetITStatus(USART2, USART_IT_TXE) != RESET)                   //这段是为了避免STM32 USART 第一个字节发不出去的BUG 
  { 
     USART_ITConfig(USART2, USART_IT_TXE, DISABLE);					     //禁止发缓冲器空中断, 
  }	
  
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值