文章内容仅个人的理解,如有错误还请各位多多包涵
参考:b站:海创电子工作室
硬件
单片机:stm32f103c8t6
一、带大家了解这款单片机串口所在的引脚
一共有三个串口
二、使用方法
2.1原理
看不懂是吧,没关系,知道用就行
这是初始化串口配置
代码,以串口1举例
/* 串口1初始化 */
void USART1_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;//gpio口配置
USART_InitTypeDef USART_InitStructure;//串口配置
NVIC_InitTypeDef NVIC_InitStructure;//中断配置
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
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
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
USART_InitStructure.USART_BaudRate = 115200;//串口波特率
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
//Usart1 NVIC 配置
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
USART_Cmd(USART1, ENABLE); //打开串口
}
//接收中断函数
/* 中断1 */
void USART1_IRQHandler(void) //USART中断函数
{
//写自己需要执行的操作,这里是串口1接收到的数据存在data1里,在用串口2发送
u16 Data1;
while(USART_GetITStatus(USART1, USART_IT_RXNE) == RESET); //如果USART1接收
Data1 =USART_ReceiveData(USART1); //将USART1接收到的数据赋值给
USART_SendData(USART2,Data1);
USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除USART1的接收中断标志位
}
//知道加上就好,不用看懂
/* 加入以下代码, 支持printf函数, 而不需要选择use MicroLIB */
#if 1
#if (__ARMCC_VERSION >= 6010050) /* 使用AC6编译器时 */
__asm(".global __use_no_semihosting\n\t"); /* 声明不使用半主机模式 */
__asm(".global __ARM_use_no_argv \n\t"); /* AC6下需要声明main函数为无参数格式,否则部分例程可能出现半主机模式 */
#else
/* 使用AC5编译器时, 要在这里定义__FILE 和 不使用半主机模式 */
#pragma import(__use_no_semihosting)
struct __FILE
{
int handle;
/* Whatever you require here. If the only file you are using is */
/* standard output using printf() for debugging, no file handling */
/* is required. */
};
#endif
/* 不使用半主机模式,至少需要重定义_ttywrch\_sys_exit\_sys_command_string函数,以同时兼容AC6和AC5模式 */
看不懂中断函数看这里
三、ussrt.h与usart.c
#ifndef __USART_H
#define __USART_H
#include "stm32f10x.h"
#include "delay.h"
#include "stdio.h"
#include "string.h"
#include <stdarg.h>
#include "wifi.h" // Device header
#include "OLED.h" /*这里使用的是串口1(a9,a10)
串口2(a2,a3)
串口3(b10,b11)
*/
/* 一、流程
1确定1-3串口
1.2打开串口时钟以及所对应引脚时钟
1.3初始化引脚和串口
1.4打开串口
2串口中断(*使用中断要保证程序一直再运行)
2.1配置串口中断
2.2打开中断
3.打开串口
二、可以使用printf打印()使用的是串口1
u2_printf(使用的是串口2)
*/
void USART1_init(void);//初始化
void USART2_init(void);//初始化
void USART_SendByte(USART_TypeDef* USARTx,uint16_t Data);
void USART_SendString(USART_TypeDef* USARTx, char *str);//发送字符串
uint8_t USART_ReceiyeByte(USART_TypeDef* USARTx);
void u2_printf(char* fmt, ...);
#endif
usart.c
#include "usart.h"
/*
*/
/* 加入以下代码, 支持printf函数, 而不需要选择use MicroLIB */
#if 1
#if (__ARMCC_VERSION >= 6010050) /* 使用AC6编译器时 */
__asm(".global __use_no_semihosting\n\t"); /* 声明不使用半主机模式 */
__asm(".global __ARM_use_no_argv \n\t"); /* AC6下需要声明main函数为无参数格式,否则部分例程可能出现半主机模式 */
#else
/* 使用AC5编译器时, 要在这里定义__FILE 和 不使用半主机模式 */
#pragma import(__use_no_semihosting)
struct __FILE
{
int handle;
/* Whatever you require here. If the only file you are using is */
/* standard output using printf() for debugging, no file handling */
/* is required. */
};
#endif
/* 不使用半主机模式,至少需要重定义_ttywrch\_sys_exit\_sys_command_string函数,以同时兼容AC6和AC5模式 */
int _ttywrch(int ch)
{
ch = ch;
return ch;
}
/* 定义_sys_exit()以避免使用半主机模式 */
void _sys_exit(int x)
{
x = x;
}
char *_sys_command_string(char *cmd, int len)
{
return NULL;
}
/* FILE 在 stdio.h里面定义. */
FILE __stdout;
/* 重定义fputc函数, printf函数最终会通过调用fputc输出字符串到串口 ,用到串口一
其中串口可根据实际使用情况调整 */
int fputc(int ch, FILE *f)
{
while ((USART1->SR & 0X40) == 0); /* 等待上一个字符发送完成 */
USART1->DR = (uint8_t)ch; /* 将要发送的字符 ch 写入到DR寄存器 */
return ch;
}
#endif
/***********************************************END*******************************************/
/* 打印配置用的是串口2,得初始化串口2 */
void u2_printf(char* fmt, ...)
{
int i;
int len;
char buffer[50]; //足够容纳才可以,可以搞大点
va_list args;
va_start(args, fmt);
vsprintf(buffer, fmt, args);
va_end(args);
len = strlen(buffer);
for( i=0; i<len; i++)
{
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); //等待发送完毕
USART_SendData(USART2, buffer[i]); //发送一个字符
}
}
/* 串口1初始化 */
void USART1_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
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
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
USART_InitStructure.USART_BaudRate = 115200;//串口波特率
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
//Usart1 NVIC 配置
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
USART_Cmd(USART1, ENABLE); //打开串口
}
/* 串口2初始化 */
void USART2_init(void)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); //使能USART2,GPIOA时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能USART2,GPIOA时钟
//USART2_TX GPIOA.2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.2
//USART2_RX GPIOA.3初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.3
//Usart2 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART2_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 = 115200;//串口波特率
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(USART2, &USART_InitStructure); //初始化串口2
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断
USART_Cmd(USART2, ENABLE); //使能串口2
}
/* 发送*/
void USART_SendByte(USART_TypeDef *USARTx,uint16_t Data)
{
assert_param(IS_USART_ALL_PERIPH(USARTx));
assert_param(IS_USART_DATA(Data));
USARTx->DR=(Data&(uint16_t)0x01FF);
while (USART_GetFlagStatus(USARTx,USART_FLAG_TXE)==RESET);
}
void USART_SendString(USART_TypeDef* USARTx, char *str)
{
while(*str != '\0')
{
USART_SendByte(USARTx, *str++);
}
while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);
}
/* 接受 */
uint8_t USART_ReceiyeByte(USART_TypeDef *USARTx)
{
while(USART_GetFlagStatus(USARTx,USART_FLAG_RXNE)==RESET);
return (uint8_t)USART_ReceiveData(USARTx);
}
/* 中断1 */
void USART1_IRQHandler(void) //USART中断函数
{
u16 Data1;
while(USART_GetITStatus(USART1, USART_IT_RXNE) == RESET); //如果USART1接收中断SET
Data1 =USART_ReceiveData(USART1); //将USART1接收到的数据赋值给Data
USART_SendData(USART2,Data1); //用串口2将Data的值发送出去
//--------------------------
judge_receive_end();
//-----------------
USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除USART1的接收中断标志位
}
void USART2_IRQHandler(void) //串口2中断服务程序
{
u16 Data2;
while(USART_GetITStatus(USART2, USART_IT_RXNE) == RESET); //如果USART1接收中断SET
Data2 =USART_ReceiveData(USART2); //将USART接收到的数据赋值给Data
USART_SendData(USART2,Data2); //将Data的值发送出去
USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除USART1的接收中断标志位
}