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); //禁止发缓冲器空中断,
}
}