注意USART的引脚请自行查阅相应的数据手册
本模块主要实现功能
实现开发板与电脑通信,在开发板上电时通过 USART 发送一串字符串给电脑,然后开发板进入中断接收等待状态,如果电脑有发送数据过来,开发板就会产生中断,我们在中断服务函数接收数据,并马上把数据返回发送给电脑
在USART–串口通信一文中有详细解释,这里就不做详细解释
这是使用的宏定义
#ifndef __BSP_USART_H
#define __BSP_USART_H
#include "stm32f10x.h"
#include
/**
* 串口宏定义,不同的串口挂载的总线和IO不一样,移植时需要修改这几个宏
* 1-修改总线时钟的宏,uart1挂载到apb2总线,其他uart挂载到apb1总线
* 2-修改GPIO的宏
*/
#define DEBUG_USART1 1
#define DEBUG_USART2 0
#define DEBUG_USART3 0
#define DEBUG_USART4 0
#define DEBUG_USART5 0
#if DEBUG_USART1
// 串口1-USART1
#define DEBUG_USARTx USART1
#define DEBUG_USART_CLK RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOA
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9
#define DEBUG_USART_RX_GPIO_PORT GPIOA
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10
#define DEBUG_USART_IRQ USART1_IRQn
#define DEBUG_USART_IRQHandler USART1_IRQHandler
#elif DEBUG_USART2
// 串口2-USART2
#define DEBUG_USARTx USART2
#define DEBUG_USART_CLK RCC_APB1Periph_USART2
#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOA
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_2
#define DEBUG_USART_RX_GPIO_PORT GPIOA
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_3
#define DEBUG_USART_IRQ USART2_IRQn
#define DEBUG_USART_IRQHandler USART2_IRQHandler
#elif DEBUG_USART3
// 串口3-USART3
#define DEBUG_USARTx USART3
#define DEBUG_USART_CLK RCC_APB1Periph_USART3
#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOB)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOB
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
#define DEBUG_USART_RX_GPIO_PORT GPIOB
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11
#define DEBUG_USART_IRQ USART3_IRQn
#define DEBUG_USART_IRQHandler USART3_IRQHandler
#elif DEBUG_USART4
// 串口4-UART4
#define DEBUG_USARTx UART4
#define DEBUG_USART_CLK RCC_APB1Periph_UART4
#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOC
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
#define DEBUG_USART_RX_GPIO_PORT GPIOC
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11
#define DEBUG_USART_IRQ UART4_IRQn
#define DEBUG_USART_IRQHandler UART4_IRQHandler
#elif DEBUG_USART5
// 串口5-UART5
#define DEBUG_USARTx UART5
#define DEBUG_USART_CLK RCC_APB1Periph_UART5
#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOC
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_12
#define DEBUG_USART_RX_GPIO_PORT GPIOD
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_2
#define DEBUG_USART_IRQ UART5_IRQn
#define DEBUG_USART_IRQHandler UART5_IRQHandler
#endif
void USART_Config(void);
void Usart_SendByte(USART_TypeDef* pUSARTx,uint8_t data);
void Usart_SendHalfWord(USART_TypeDef * pUSARTx,uint16_t data);
void Usart_SendArray(USART_TypeDef * pUSARTx,uint8_t *array,uint8_t num);
void Usart_SendStr(USART_TypeDef * pUSARTx,uint8_t *str);
#endif
首先设置中断的优先级
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitSructure;
// 进行嵌套向量中断控制器的选择
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// 配置USART为中断源
NVIC_InitSructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
// 抢断优先级
NVIC_InitSructure.NVIC_IRQChannelPreemptionPriority = 1;
// 子优先级
NVIC_InitSructure.NVIC_IRQChannelSubPriority = 1;
// 使能中断
NVIC_InitSructure.NVIC_IRQChannelCmd = ENABLE;
// 初始化配置NVIC
NVIC_Init(& NVIC_InitSructure);
}
其次是USART串口的初始化
void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// 打开串口GPIO的时钟
DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK,ENABLE);
// 打开串口外设的时钟
DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK,ENABLE);
// 初始化GPIO, 将USART Tx配置为推挽复用模式
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DEBUG_USART_TX_GPIO_PORT,&GPIO_InitStructure);
// 将USART Rx的GPIO配置为浮空输入模式
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(DEBUG_USART_RX_GPIO_PORT,&GPIO_InitStructure);
// 配置串口的工作的参数
// 配置波特率
USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
// 配置字数据长
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
// 配置停止位
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(DEBUG_USARTx,& USART_InitStructure);
// 串口中断优先级配置
NVIC_Configuration();
// 使能串口接收中断
USART_ITConfig(DEBUG_USARTx,USART_IT_RXNE,ENABLE);
// 使能串口(其实是打开UE)
USART_Cmd(DEBUG_USARTx,ENABLE);
}
注意初始化串口时,分别初始化串口的TX(推挽复用)RX(浮空输入)两个引脚后,再配置串口的结构体的参数。再调用前面的设置中断的优先级。使能串口接收中断
上面完成的是串口初始化的代码,下面是具体实现数据发送的功能函数
// 发送一个字节
void Usart_SendByte(USART_TypeDef* pUSARTx,uint8_t data)
{
USART_SendData(pUSARTx,data);
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE) == RESET);
}
// 发射两个字节
void Usart_SendHalfWord(USART_TypeDef * pUSARTx,uint16_t data)
{
uint8_t temp_h,temp_l;
temp_h = (data & 0xff00) >> 8;
temp_l = data & 0xff;
USART_SendData(pUSARTx,temp_h);
while( USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE) == RESET );
USART_SendData(pUSARTx,temp_l);
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE));
}
// 发送8位数据的数组
void Usart_SendArray(USART_TypeDef * pUSARTx,uint8_t *array,uint8_t num)
{
uint8_t i;
for(i = 0; i < num;i++)
{
Usart_SendByte(pUSARTx,*array++);
}
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC) == RESET);
}
// 发送字符串
void Usart_SendStr(USART_TypeDef * pUSARTx,uint8_t *str)
{
uint8_t i = 0;
do
{
Usart_SendByte(pUSARTx,*(str + i));
i++;
}while(*(str + i) != '\0');
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC) == RESET);
}
// 重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch,FILE *f)
{
// 发送一个字节到串口
USART_SendData(DEBUG_USARTx,(uint8_t)ch);
// 等待发送完成
while(USART_GetFlagStatus(DEBUG_USARTx,USART_FLAG_TXE) == RESET);
return (ch);
}
// 重定向c库函数scanf到串口,重写向后可使用的scanf,getchar函数
int fgetc(FILE *f)
{
// 等待串口输入数据
while (USART_GetFlagStatus(DEBUG_USARTx,USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(DEBUG_USARTx);
}
// 串口中断函数
void DEBUG_USART_IRQHandler(void)
{
uint8_t ucTemp;
if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE) != RESET)
{
ucTemp = USART_ReceiveData(DEBUG_USARTx);
USART_SendData(DEBUG_USARTx,ucTemp);
}
}
这是串口完成接收时,接收到数据后,存储在ucTemp然后再发送回来他接收到的数据
# include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_usart.h"
void Delay( uint32_t count)
{
for(;count != 0;count--);
}
int main(void)
{
USART_Config();
printf("串口printf函数测试\n");
putchar('p');
while(1){
}
}
其实这里主要还是就是完成串口的初始化
主要的串口初始化和接收函数和上面一样
我们这里主要通过接收到的数据控制小灯
小灯初始化请见:C8T6超绝模块–点亮小灯
而与上面的差别,主要体现在主函数里面
# include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_usart.h"
int main(void)
{
USART_Config();
uint8_t ch;
LED_GPIO_Config();
while(1){
printf("这是串口控制LED的程序\n");
ch = getchar();
printf("ch=%c\n",ch);
switch(ch)
{
case '1':
LED_G(ON);
break;
case '2':
LED_G(OFF);
break;
default:LED_G(OFF);
}
}
}
这里主要通过getchar()来把USART返回的值存储到ch中,然后再通过ch的值进行判断,来进行点亮或者熄灭小灯
但是这里要注意点一点是:
我们使用这个getchar()要实现返回接收到的串口数据值,需要实现他的重定向
在上面的代码主要体现在这一块
// 重定向c库函数scanf到串口,重写向后可使用的scanf,getchar函数
int fgetc(FILE *f)
{
// 等待串口输入数据
while (USART_GetFlagStatus(DEBUG_USARTx,USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(DEBUG_USARTx);
}
判断是否接受完成,如果接收完成,就返回接收到的值