【STM32F103ZET6——库函数】4.串口通讯

目录

配置串口引脚

引脚图

中断优先级分组

使能时钟

配置中断优先级

配置串口

重写中断服务函数

清空中断标志位

获取中断标志位

接收函数

打印数据

例程

例程说明

main.h

main.c

usart.h

usart.c

配置串口引脚

引脚图

  1. 配置引脚号

  2. 配置引脚速度

  3. 配置引脚的模式

  4. 引脚初始化

cpp 复制代码
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

中断优先级分组

cpp 复制代码
/*
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);//中断优先级分组

使能时钟

cpp 复制代码
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟

配置中断优先级

  1. 配置中断的串口

  2. 配置抢占优先级

  3. 配置子优先级

  4. 通道使能

  5. 接收中断使能

cpp 复制代码
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);//接收中断使能

配置串口

  1. 配置波特率

  2. 配置数据模式

  3. 配置停止位

  4. 配置奇偶校验位

  5. 配置硬件流传输

  6. 配置收发模式

  7. 串口初始化

  8. 串口使能

cpp 复制代码
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);//串口使能

重写中断服务函数

注意:中断服务函数的函数已经固定,重新定义相同名字的函数即可,在定义好的函数里写中断的操作,哪个串口发生中断就得重定义哪个串口中断的函数

cpp 复制代码
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);
    }
}

清空中断标志位

在中断服务函数里进行操作。

cpp 复制代码
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);

USART_ClearITPendingBit(USART1,USART_IT_RXNE);

获取中断标志位

cpp 复制代码
/*
不仅会判断标志位是否置1,同时还会判断是否使能了相应的中断
*/
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);

USART_GetITStatus(USART1, USART_IT_RXNE);

接收函数

cpp 复制代码
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);

Res =USART_ReceiveData(USART1);	//读取接收到的数据

打印数据

注意:得加上下面函数,才能像C语言那样打印到终端,在这里是打印到串口调试助手上

cpp 复制代码
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

cpp 复制代码
#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

cpp 复制代码
#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

cpp 复制代码
#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

cpp 复制代码
#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);
}
相关推荐
沐怡旸21 小时前
【底层机制】std::string 解决的痛点?是什么?怎么实现的?怎么正确用?
c++·面试
River4161 天前
Javer 学 c++(十三):引用篇
c++·后端
感哥1 天前
C++ std::set
c++
侃侃_天下1 天前
最终的信号类
开发语言·c++·算法
博笙困了1 天前
AcWing学习——差分
c++·算法
青草地溪水旁1 天前
设计模式(C++)详解—抽象工厂模式 (Abstract Factory)(2)
c++·设计模式·抽象工厂模式
青草地溪水旁1 天前
设计模式(C++)详解—抽象工厂模式 (Abstract Factory)(1)
c++·设计模式·抽象工厂模式
感哥1 天前
C++ std::vector
c++
zl_dfq1 天前
C++ 之【C++11的简介】(可变参数模板、lambda表达式、function\bind包装器)
c++
每天回答3个问题1 天前
UE5C++编译遇到MSB3073
开发语言·c++·ue5