基于STM32完成串口通信
一、概述:
本文先通过最开始的LED灯程序完成寄存器与库函数的一个对比,然后通过串口完成stm32与上位机(PC机)的串口通信
二、库函数与寄存器的区别
1、库函数与寄存器的区别:
STM32对寄存器操作和对库函数操作的区别主要在于两个点
1、寄存器是直接对芯片的寄存器操作,相对库函数来说,整个程序更加高效,在需要大量处理数据的时候,寄存器能比库函数相对快的处理速度完成
2、库函数相比寄存器来说,我们更容易理解,工程师、编程人员更容易学会如何去应用函数来完成功能。也能够更加高效的完成主程序的撰写。
2、代码对比:
1、寄存器:
#include "led.h"
void LED_Init(void)
{
RCC->APB2ENR|=1<<3; //使能PORTB时钟
RCC->APB2ENR|=1<<6; //使能PORTE时钟
GPIOB->CRL&=0XFF0FFFFF;
GPIOB->CRL|=0X00300000;//PB.5 推挽输出
GPIOB->ODR|=1<<5; //PB.5 输出高
GPIOE->CRL&=0XFF0FFFFF;
GPIOE->CRL|=0X00300000;//PE.5推挽输出
GPIOE->ODR|=1<<5; //PE.5输出高
}
2、库函数:
#include "led.h"
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE); //使能PB,PE端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED0-->PB.5 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB.5
GPIO_SetBits(GPIOB,GPIO_Pin_5); //PB.5 输出高
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED1-->PE.5 端口配置, 推挽输出
GPIO_Init(GPIOE, &GPIO_InitStructure); //推挽输出 ,IO口速度为50MHz
GPIO_SetBits(GPIOE,GPIO_Pin_5); //PE.5 输出高
}
总结
通过代码的直观的对比,对寄存器的操作我们没有一个最直观的感受,我们还需要去查找相应的IO口的寄存器地址,但是通过库函数操作IO口,我们就能很直接的看到不同设置的功能。
3、两种方式所需要的库的区别
1、寄存器:
2、库函数:
总结
通过两种方式的所需要的库能够看出,库函数所需要的库比寄存器操作要多得多,所需要的底层开发程序就更多,而且库函数根本也还是对寄存器的操作,所以库函数相比寄存器运行要慢一点。
三、STM32的串口通信USART
1、构建添加需要的库
- 注释:这些库函数商家资料都有,我主要演示如何使用。
2、usart_init函数:
void uart_init(u32 bound){
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
//USART1_RX GPIOA.10初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
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
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
USART_Cmd(USART1, ENABLE); //使能串口1
}
主要步骤包括:
- 串口和GPIO引脚时钟使能
- 串口复位
- GPIO端口初始化模式设置
- 串口参数初始化
- 初始化中断方式和中断等级NVIC并且开启中断
- 使能串口
3、主函数main:
1:函数体
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
int main(void)
{
u16 t0,t1,t;
u16 len;
u16 times=0;
char *pt=" Hello windows";
u8 *on="goon stm32";
u8 *off="stop stm32";
u8 flag=0; //标志如果是1的话,停止发送数据
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
LED_Init(); //LED端口初始化
KEY_Init(); //初始化与按键连接的硬件接口
while(1)
{
//给上位机连续发送Hello world
if(!flag)
{
times++;
if(times%100==0)
{
len=14;
for(t=0;t<len;t++)
{
USART_SendData(USART1,pt[t]);//向串口1发送数据
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
}
printf("\r\n\r\n");//插入换行
USART_RX_STA=0;
}
if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
delay_ms(10);
}
//接收上位机的发送,并判断是否停止
if(USART_RX_STA&0x8000)
{
len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
for(t0=0;t0<10;t0++)
if(off[t0]!=USART_RX_BUF[t0])//如果出现不等,那么就继续发送
{
flag=flag;
break;
}
for(t1=0;t1<10;t1++)
if(on[t1]!=USART_RX_BUF[t1])//如果出现不等,那么就继续发送
{
flag=flag;
break;
}
if(t0==10)//如果都相等,那么停止发送
{
flag=1;
printf("已收到停止命令,输出停止\r\n");
USART_RX_STA=0;
continue;
}
if(t1==10)//如果都相等,那么停止发送
{
flag=0;
printf("已收到继续命令,输出继续\r\n");
USART_RX_STA=0;
continue;
}
printf("\r\n\r\n");//插入换行
USART_RX_STA=0;
}
}
}
- 功能介绍:当灯在闪烁时,系统正常工作,打开串口时,调试助手会一直输出Hello windows,当我们给32发送stop stm32时,串口停止向上位机发送,当我们给32发送 goon stm32时,他们会继续输出Hello windows。
2:功能演示:
灯闪烁情况
4、总结:
通过串口与上位机联系起来,这样我们就不用每次都调试代码来设置参数,我们能够直接通过上位机发指令来设置参数,这样有利于我们后面学习PID的参数设置的时候,通过上位机的控制来快速修改参数。