【STM32F103ZET6——库函数】4.串口通讯
目录
配置串口引脚
引脚图
中断优先级分组
使能时钟
配置中断优先级
配置串口
重写中断服务函数
清空中断标志位
获取中断标志位
接收函数
打印数据
例程
例程说明
main.h
main.c
usart.h
usart.c
配置串口引脚
引脚图
配置引脚号
配置引脚速度
配置引脚的模式
引脚初始化
GPIO_InitTypeDef GPIO;
//USART1_TX GPIOA.9
GPIO.GPIO_Pin = GPIO_Pin_9; //PA9
GPIO.GPIO_Speed = GPIO_Speed_50MHz;
GPIO.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO);//初始化GPIOA9
//USART1_RX GPIOA.10初始化
GPIO.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO);//初始化GPIOA.10
中断优先级分组
/*
zu_bie:
NVIC_PriorityGroup_0
NVIC_PriorityGroup_1
NVIC_PriorityGroup_2
NVIC_PriorityGroup_3
NVIC_PriorityGroup_4
*/
void NVIC_PriorityGroupConfig(zu_bie);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组
使能时钟
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
配置中断优先级
配置中断的串口
配置抢占优先级
配置子优先级
通道使能
接收中断使能
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);//接收中断使能
NVIC_InitTypeDef ZhongDuan;
//Usart1 NVIC 配置
ZhongDuan.NVIC_IRQChannel = USART1_IRQn;
ZhongDuan.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级1
ZhongDuan.NVIC_IRQChannelSubPriority = 1; //子优先级1
ZhongDuan.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&ZhongDuan); //根据指定的参数初始化VIC寄存器
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//接收中断使能
配置串口
配置波特率
配置数据模式
配置停止位
配置奇偶校验位
配置硬件流传输
配置收发模式
串口初始化
串口使能
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);//串口使能
USART_InitTypeDef ChuanKou;
//USART 初始化设置
ChuanKou.USART_BaudRate = bound;//串口波特率
ChuanKou.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
ChuanKou.USART_StopBits = USART_StopBits_1;//一个停止位
ChuanKou.USART_Parity = USART_Parity_No;//无奇偶校验位
ChuanKou.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
ChuanKou.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1,&ChuanKou);//串口初始化
USART_Cmd(USART1,ENABLE);//串口使能
重写中断服务函数
注意:中断服务函数的函数已经固定,重新定义相同名字的函数即可,在定义好的函数里写中断的操作,哪个串口发生中断就得重定义哪个串口中断的函数
void USART1_IRQHandler();
void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 JiaoYan_Wei=0;
u8 j;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
Res =USART_ReceiveData(USART1); //读取接收到的数据
data[flag_1]=Res;
flag_1++;
if(flag_1==6) {
flag_1=0;
flag=1;
}
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}
}
清空中断标志位
在中断服务函数里进行操作。
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
获取中断标志位
/*
不仅会判断标志位是否置1,同时还会判断是否使能了相应的中断
*/
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);
USART_GetITStatus(USART1, USART_IT_RXNE);
接收函数
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
Res =USART_ReceiveData(USART1); //读取接收到的数据
打印数据
注意:得加上下面函数,才能像C语言那样打印到终端,在这里是打印到串口调试助手上
int fputc(int ch, FILE *f)
{
USART_SendData(USART1, (uint8_t) ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return (ch);
}
例程
例程说明
1.编写主程序,初始化串口1,设置波特率为9600,无校验,数据位8位,停止位1位。
2.编写中断服务程序代码实现将接收到的数据保存下来。
3、数据格式为0xaa,0x55,0xxx(有效控制字节), 校验字节(前数相加-1),0x0d,0x0a 。(前两个是头码,后两个是结束码)
4.分析保存的数据,如果数据正确,则将控制单片机进行对应的动作,并把收到的数据发回。
5、.控制动作包括led1、led2和蜂鸣器,控制协议自定,比如:
0x01 Led1亮 0x02 Led1灭 0x08 Led2亮 0x09 Led2灭 0x15 蜂鸣器响 0x16 蜂鸣器不响
main.h
#ifndef _MAIN_H_
#define _MAIN_H_
#include "stm32f10x.h" // Device header
#include "stm32f10x_gpio.h" // Keil::Device:StdPeriph Drivers:GPIO
#include "stm32f10x_tim.h" // Keil::Device:StdPeriph Drivers:TIM
#include <stm32f10x_rcc.h>
#include <stm32f10x_usart.h>
#include <stm32f10x_sdio.h>
#include <misc.h>
#include <stdio.h>
#include <delay.h>
#include "timch.h"
#include "bsp_SysTick.h"
#include "led.h"
#include "Key.h"
#include "usart.h"
#include "FengMingQi.h"
#endif
main.c
#include "main.h"
extern u8 data[6];
extern u8 flag_1;
extern u8 flag;
int main() {
u8 key_num;
u8 FMQ=0;
u8 j;
u8 JiaoYan_Wei=0;
uart_init(9600);
LED_Init();
Key_Init();
FengMingQi_Init();
while(1) {
if(flag==1){
flag=0;
printf("\rok\n%x %x %x %x %x %x",data[0],data[1],data[2],data[3],data[4],data[5]);
JiaoYan_Wei=data[0]+data[1]+data[2]-1;
if((data[0]==0xaa)&&(data[1]==0x55)&&(JiaoYan_Wei==data[3])&&(data[4]==0x0d)&&(data[5]==0x0a)){
switch(data[2]) {
case 0x01: {//aa 55 01 ff 0d 0a
LED_R_NO();
break;
}
case 0x02: {//aa 55 02 00 0d 0a
LED_R_OFF();
break;
}
case 0x08: {//aa 55 08 06 0d 0a
LED_G_NO();
break;
}
case 0x09: {//aa 55 09 07 0d 0a
LED_G_OFF();
break;
}
case 0x15: {//aa 55 15 13 0d 0a
FengMingQi_NO();
break;
}
case 0x16: {//aa 55 16 14 0d 0a
FengMingQi_OFF();
break;
}
}
}
}
}
}
usart.h
#ifndef __USART_H
#define __USART_H
#include "stdio.h"
#include "sys.h"
#include "led.h"
#include "FengMingQi.h"
#include "delay.h"
extern u8 Res;
void uart_init(u32 bound);
void USART1_IRQHandler();
#endif
usart.c
#include "usart.h"
void uart_init(u32 bound) {
//GPIO端口设置
GPIO_InitTypeDef GPIO;
USART_InitTypeDef ChuanKou;
NVIC_InitTypeDef ZhongDuan;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
//USART1_TX GPIOA.9
GPIO.GPIO_Pin = GPIO_Pin_9; //PA9
GPIO.GPIO_Speed = GPIO_Speed_50MHz;
GPIO.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO);//初始化GPIOA9
//USART1_RX GPIOA.10初始化
GPIO.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO);//初始化GPIOA.10
//Usart1 NVIC 配置
ZhongDuan.NVIC_IRQChannel = USART1_IRQn;
ZhongDuan.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级1
ZhongDuan.NVIC_IRQChannelSubPriority = 1; //子优先级1
ZhongDuan.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&ZhongDuan); //根据指定的参数初始化VIC寄存器
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//接收中断使能
//USART 初始化设置
ChuanKou.USART_BaudRate = bound;//串口波特率
ChuanKou.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
ChuanKou.USART_StopBits = USART_StopBits_1;//一个停止位
ChuanKou.USART_Parity = USART_Parity_No;//无奇偶校验位
ChuanKou.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
ChuanKou.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1,&ChuanKou);//串口初始化
USART_Cmd(USART1,ENABLE);//串口使能
}
u8 data[6];
u8 Res;
u8 flag_1=0;
u8 flag;
void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 JiaoYan_Wei=0;
u8 j;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
Res =USART_ReceiveData(USART1); //读取接收到的数据
data[flag_1]=Res;
flag_1++;
if(flag_1==6) {
flag_1=0;
flag=1;
}
USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除中断标志位
}
}
int fputc(int ch, FILE *f)
{
USART_SendData(USART1, (uint8_t) ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return (ch);
}