妙,醍醐灌顶。。。
其他元素对应取值范围可用相同方法类似可查。。。
妙妙妙,一键替换。。。
串口基地址设置 (对应好几个串口选择用哪一个)
串口波特率设置
剩下一些参数的配置同波特率类似。。。
注意左右移式中是其左操作数移动一定的位置。。。
注意串口要用到PA9和PA10。。。
关于其中的使能和失能平衡问题。。。
最终发送和接受成功(注意串口线要连接别光连个ST-Link成大怨种,注意波特率要对应且需要发送其才显示,不发送不显示,注意其输入的东西必须是对应8位二进制能够表示的才可以)。。。
对应一个字符的串口实验。。。
main.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
//int temp[10] = {15,14,13};
//int temp;
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
delay_init(168); /* 延时初始化 */
led_init(); /* 初始化LED */
usart_init(115200);//波特率设置
printf("请输入一个英文字符:\r\n");
while(1)
{
if(g_usart1_rx_flag==1){
printf("您输入的字符为:");
HAL_UART_Transmit(&g_uart1_handle,(uint8_t *)g_rx_buffer,1,1000);
while(__HAL_UART_GET_FLAG(&g_uart1_handle,UART_FLAG_TC)!=1);
printf("\r\n");
g_usart1_rx_flag = 0;
}
else{
delay_ms(10);
}
}
}
usart.h
#ifndef _USART_H
#define _USART_H
#include "stdio.h"
#include "./SYSTEM/sys/sys.h"
/*******************************************************************************************************/
/* 引脚 和 串口 定义
* 默认是针对USART1的.
* 注意: 通过修改这12个宏定义,可以支持USART1~UART7任意一个串口.
*/
#define GPIO_AF7_USART1 ((uint8_t)0x07) /* USART1 Alternate Function mapping */
#define GPIO_AF7_USART2 ((uint8_t)0x07) /* USART2 Alternate Function mapping */
#define GPIO_AF7_USART3 ((uint8_t)0x07) /* USART3 Alternate Function mapping */
#define GPIO_AF7_I2S3ext ((uint8_t)0x07) /* I2S3ext_SD Alternate Function mapping */
extern UART_HandleTypeDef g_uart1_handle; /* UART句柄 */
extern uint8_t g_rx_buffer[1];//HAL库使用的串口数据缓冲区
//注意其声明是不能赋值的
extern uint8_t g_usart1_rx_flag;//串口接受到数据标志
void usart_init(uint32_t baudrate); /* 串口初始化函数 */
#endif
usart.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/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*******************************************/
UART_HandleTypeDef g_uart1_handle; /* UART句柄 */
/**
* @brief 串口X初始化函数
* @param baudrate: 波特率, 根据自己需要设置波特率值
* @note 注意: 必须设置正确的时钟源, 否则串口波特率就会设置异常.
* 这里的USART的时钟源在sys_stm32_clock_init()函数中已经设置过了.
* @retval 无
*/
uint8_t g_rx_buffer[1];//HAL库使用的串口数据缓冲区
uint8_t g_usart1_rx_flag = 0;//串口接受到数据标志
//串口一初始化函数
void usart_init(uint32_t baudrate)//结构体指针
{
g_uart1_handle.Instance = USART1; /* USART1 */
g_uart1_handle.Init.BaudRate = baudrate; /* 波特率 */
g_uart1_handle.Init.WordLength = UART_WORDLENGTH_8B; /* 字长为8位数据格式 */
g_uart1_handle.Init.StopBits = UART_STOPBITS_1; /* 一个停止位 */
g_uart1_handle.Init.Parity = UART_PARITY_NONE; /* 无奇偶校验位 */
g_uart1_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 无硬件流控 */
g_uart1_handle.Init.Mode = UART_MODE_TX_RX; /* 收发模式 */
HAL_UART_Init(&g_uart1_handle); /* HAL_UART_Init()会使能UART1 */
HAL_UART_Receive_IT(&g_uart1_handle,(uint8_t *)g_rx_buffer,1);
}
/**
* @brief UART底层初始化函数
* @param huart: UART句柄类型指针
* @note 此函数会被HAL_UART_Init()调用
* 完成时钟使能,引脚配置,中断配置
* @retval 无
*/
//串口一MSP回调函数
void HAL_UART_MspInit(UART_HandleTypeDef *huart)//注意其形参为结构体指针也即句柄也即回调函数
{
GPIO_InitTypeDef gpio_init_struct;
//判断其是否是相应串口
if(huart->Instance == USART1) /* 如果是串口1,进行串口1 MSP初始化 */
{
/* (1)使能USART1和对应IO时钟,(2)初始化IO,(3)使能USART1中断,设置优先级 */
__HAL_RCC_USART1_CLK_ENABLE(); /* USART1 时钟使能 */
__HAL_RCC_GPIOA_CLK_ENABLE(); /* 发送引脚时钟使能 ,接收引脚时钟使能 */
gpio_init_struct.Pin = GPIO_PIN_9; /* TX引脚 */
gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出 */
//注意其输出模式对应的上拉电阻和下拉电阻都呈关闭状态
//gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
//gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
gpio_init_struct.Alternate = GPIO_AF7_USART1; /* 复用为USART1 */
HAL_GPIO_Init(GPIOA, &gpio_init_struct); /* 初始化发送引脚 */
gpio_init_struct.Pin = GPIO_PIN_10; /* RX引脚 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Alternate = GPIO_AF7_USART1; /* 复用为USART1 */
HAL_GPIO_Init(GPIOA, &gpio_init_struct); /* 初始化接收引脚 */
HAL_NVIC_SetPriority(USART1_IRQn,3,3);
HAL_NVIC_EnableIRQ(USART1_IRQn);
#if USART_EN_RX
HAL_NVIC_EnableIRQ(USART1_IRQn); /* 使能USART1中断通道 */
HAL_NVIC_SetPriority(USART1_IRQn, 3, 3); /* 抢占优先级3,子优先级3 */
#endif
}
}
/**
* @brief Rx传输回调函数
* @param huart: UART句柄类型指针
* @retval 无
*/
//串口数据接受完回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
//注意当下只使用一个串口故其这样写没有问题,相应多个串口时要额外加以判断。。。
g_usart1_rx_flag = 1;
}
/**
* @brief 串口1中断服务函数
* @param 无
* @retval 无
*/
//串口一中断处理函数USART1_IRQHandler()
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&g_uart1_handle); /* 调用HAL库中断处理公用函数 */
//为防止下一步接受字符时其相应中断使能。。。
HAL_UART_Receive_IT(&g_uart1_handle,(uint8_t *)g_rx_buffer,1);
}
接受多个字节数据串口 实验。。。
注意联系下图对应14和15位(如果学过编译原理想必是很好理解的)。。。
串口接受协议对应实现。。。
注意细节。。。
main.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
int main(void)
{
uint8_t len;
uint16_t times = 0;
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
delay_init(168); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
printf("Hello World!\n");
while(1)
{
if (g_usart_rx_sta & 0x8000) /* 接收到了数据? */
{
len = g_usart_rx_sta & 0x3fff; /* 得到此次接收到的数据长度 */
printf("\r\n您发送的消息为:\r\n");
//对应1000即其超时时间。。。
HAL_UART_Transmit(&g_uart1_handle,(uint8_t*)g_usart_rx_buf,len,1000); /* 发送接收到的数据 */
while(__HAL_UART_GET_FLAG(&g_uart1_handle,UART_FLAG_TC)!=SET); /* 等待发送结束 */
printf("\r\n\r\n"); /* 插入换行 */
g_usart_rx_sta = 0;
}
else
{
times++;
if (times % 5000 == 0)
{
printf("\r\n正点原子 STM32开发板 串口实验\r\n");
printf("正点原子@ALIENTEK\r\n\r\n");
}
if (times % 200 == 0) printf("请输入数据,以回车键结束\r\n");
if (times % 30 == 0) LED0_TOGGLE(); /* 闪烁LED,提示系统正在运行. */
delay_ms(10);
}
}
}
usart.h
#ifndef _USART_H
#define _USART_H
#include "stdio.h"
#include "./SYSTEM/sys/sys.h"
/*******************************************************************************************************/
/* 引脚 和 串口 定义
* 默认是针对USART1的.
* 注意: 通过修改这12个宏定义,可以支持USART1~UART7任意一个串口.
*/
#define USART_TX_GPIO_PORT GPIOA
#define USART_TX_GPIO_PIN GPIO_PIN_9
#define USART_TX_GPIO_AF GPIO_AF7_USART1
#define USART_TX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* 发送引脚时钟使能 */
#define USART_RX_GPIO_PORT GPIOA
#define USART_RX_GPIO_PIN GPIO_PIN_10
#define USART_RX_GPIO_AF GPIO_AF7_USART1
#define USART_RX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* 接收引脚时钟使能 */
#define USART_UX USART1
#define USART_UX_IRQn USART1_IRQn
#define USART_UX_IRQHandler USART1_IRQHandler
#define USART_UX_CLK_ENABLE() do{ __HAL_RCC_USART1_CLK_ENABLE(); }while(0) /* USART1 时钟使能 */
/*******************************************************************************************************/
#define USART_REC_LEN 200 /* 定义最大接收字节数 200 */
#define USART_EN_RX 1 /* 使能(1)/禁止(0)串口1接收 */
#define RXBUFFERSIZE 1 /* 缓存大小 */
extern UART_HandleTypeDef g_uart1_handle; /* UART句柄 */
extern uint8_t g_usart_rx_buf[USART_REC_LEN]; /* 接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 */
extern uint16_t g_usart_rx_sta; /* 接收状态标记 */
extern uint8_t g_rx_buffer[RXBUFFERSIZE]; /* HAL库USART接收Buffer */
void usart_init(uint32_t baudrate); /* 串口初始化函数 */
#endif
usart.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
/* 如果使用os,则包括下面的头文件即可 */
#if SYS_SUPPORT_OS
#include "os.h" /* os 使用 */
#endif
/******************************************************************************************/
/* 加入以下代码, 支持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*******************************************/
#if USART_EN_RX /* 如果使能了接收 */
/* 接收缓冲, 最大USART_REC_LEN个字节. */
uint8_t g_usart_rx_buf[USART_REC_LEN];
/* 接收状态
* bit15, 接收完成标志
* bit14, 接收到0x0d
* bit13~0, 接收到的有效字节数目
*/
uint16_t g_usart_rx_sta = 0;
uint8_t g_rx_buffer[RXBUFFERSIZE]; /* HAL库使用的串口接收缓冲 */
UART_HandleTypeDef g_uart1_handle; /* UART句柄 */
/**
* @brief 串口X初始化函数
* @param baudrate: 波特率, 根据自己需要设置波特率值
* @note 注意: 必须设置正确的时钟源, 否则串口波特率就会设置异常.
* 这里的USART的时钟源在sys_stm32_clock_init()函数中已经设置过了.
* @retval 无
*/
void usart_init(uint32_t baudrate)
{
g_uart1_handle.Instance = USART_UX; /* USART1 */
g_uart1_handle.Init.BaudRate = baudrate; /* 波特率 */
g_uart1_handle.Init.WordLength = UART_WORDLENGTH_8B; /* 字长为8位数据格式 */
g_uart1_handle.Init.StopBits = UART_STOPBITS_1; /* 一个停止位 */
g_uart1_handle.Init.Parity = UART_PARITY_NONE; /* 无奇偶校验位 */
g_uart1_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 无硬件流控 */
g_uart1_handle.Init.Mode = UART_MODE_TX_RX; /* 收发模式 */
HAL_UART_Init(&g_uart1_handle); /* HAL_UART_Init()会使能UART1 */
/* 该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量 */
HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE);
}
/**
* @brief UART底层初始化函数
* @param huart: UART句柄类型指针
* @note 此函数会被HAL_UART_Init()调用
* 完成时钟使能,引脚配置,中断配置
* @retval 无
*/
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
GPIO_InitTypeDef gpio_init_struct;
if(huart->Instance == USART_UX) /* 如果是串口1,进行串口1 MSP初始化 */
{
USART_UX_CLK_ENABLE(); /* USART1 时钟使能 */
USART_TX_GPIO_CLK_ENABLE(); /* 发送引脚时钟使能 */
USART_RX_GPIO_CLK_ENABLE(); /* 接收引脚时钟使能 */
gpio_init_struct.Pin = USART_TX_GPIO_PIN; /* TX引脚 */
gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 复用推挽输出 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
gpio_init_struct.Alternate = USART_TX_GPIO_AF; /* 复用为USART1 */
HAL_GPIO_Init(USART_TX_GPIO_PORT, &gpio_init_struct); /* 初始化发送引脚 */
gpio_init_struct.Pin = USART_RX_GPIO_PIN; /* RX引脚 */
gpio_init_struct.Alternate = USART_RX_GPIO_AF; /* 复用为USART1 */
HAL_GPIO_Init(USART_RX_GPIO_PORT, &gpio_init_struct); /* 初始化接收引脚 */
#if USART_EN_RX
HAL_NVIC_EnableIRQ(USART_UX_IRQn); /* 使能USART1中断通道 */
HAL_NVIC_SetPriority(USART_UX_IRQn, 3, 3); /* 抢占优先级3,子优先级3 */
#endif
}
}
/**
* @brief Rx传输回调函数
* @param huart: UART句柄类型指针
* @retval 无
*/
//对应接受协议
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART_UX) /* 如果是串口1 */
{
if((g_usart_rx_sta & 0x8000) == 0) /* 接收未完成 *///联系15位
{
if(g_usart_rx_sta & 0x4000) /* 接收到了0x0d *///对应已经接受到回车
{
if(g_rx_buffer[0] != 0x0a)//对应下一位不是换行
{
g_usart_rx_sta = 0; /* 接收错误,重新开始 */
}
else //对应下一位是换行
{
g_usart_rx_sta |= 0x8000; /* 接收完成了 *///联系15位
}
}
else /* 还没收到0X0D *///还没有收到回车
{
if(g_rx_buffer[0] == 0x0d)//对应下一位是回车
{
g_usart_rx_sta |= 0x4000;//联系14位
}
else//既没有收到回车而对应下一位又不是车
{
//这步极妙即其取对应的低14位对应的数组长度(也可以视为对应的数组索引和指针)
g_usart_rx_buf[g_usart_rx_sta & 0X3FFF] = g_rx_buffer[0] ;//注意该串口接受缓冲容量为一
g_usart_rx_sta++;//指针++也即对应字节数加一
if(g_usart_rx_sta > (USART_REC_LEN - 1))//注意其下标从0开使即对应接受个数超过对应接收缓存容量了过
//重新开始吧。。。
{
g_usart_rx_sta = 0; /* 接收数据错误,重新开始接收 */
}
}
}
}
HAL_UART_Receive_IT(&g_uart1_handle, (uint8_t *)g_rx_buffer, RXBUFFERSIZE);
}
}
/**
* @brief 串口1中断服务函数
* @param 无
* @retval 无
*/
void USART_UX_IRQHandler(void)
{
#if SYS_SUPPORT_OS /* 使用OS */
OSIntEnter();
#endif
HAL_UART_IRQHandler(&g_uart1_handle); /* 调用HAL库中断处理公用函数 */
#if SYS_SUPPORT_OS /* 使用OS */
OSIntExit();
#endif
}
#endif