一:前言
1、USART 数据寄存器 (USART_DR) 只有低 9 位有效,并且第 9 位数据是否有效要取决于 USART控制寄存器1(USART_CR1) 的 M 位设置,当 M 位为 0 时表示 8 位数据字长,当 M 位为 1 表示 9位数据字长(最后一位为奇偶校验位),我们一般使用 8 位数据字长
寄存器 | 作用 | 标志 |
---|---|---|
TXE:发送数据寄存器空 | 当TDR寄存器中的数据被硬件转移到移位寄存器的时候,该位被硬件置1,对USART_DR的写操作,该位清零。 | 1:数据已经被转移到移位寄存器 |
TC:发送完成 | 当包含有数据的一帧发送完成后,并且TXE=1时,由硬件将该位置“1” 。清零:软件序列清除该位(先读USART_SR,然后写入USART_DR,也就是读一下然后直接写就行了),TC位也可以通过写入“0”来清除,只有在多缓存通讯中才推荐这种清除程序。(移位寄存器也发送光了) | 1:发送完成 |
RXNE:读数据寄存器非空 | 当RDR移位寄存器中的数据被转移到USART_DR寄存器中,该位被硬件置位。对USART_DR的读操作可以将该位清零。RXNE位也可以通过写入0来清除,只有在多缓存通讯中才推荐这种清除程序。 | 1:收到数据,可以读出。 |
IDLE:监测到总线空闲 | 当检测到总线空闲时,该位被硬件置位。由软件序列清除该位(先读USART_SR,然后读USART_DR)。注意:IDLE位不会再次被置高,直到RXNE位被置起(即又检测到一次总线空闲) | 1:检测到总线空闲 |
二:结构体
typedef struct __USART_HandleTypeDef
{
USART_TypeDef *Instance; /*!< USART registers base address */
USART_InitTypeDef Init; /*!< Usart communication parameters */
uint8_t *pTxBuffPtr; /*!< Pointer to Usart Tx transfer Buffer */
uint16_t TxXferSize; /*!< Usart Tx Transfer size */
__IO uint16_t TxXferCount; /*!< Usart Tx Transfer Counter */
uint8_t *pRxBuffPtr; /*!< Pointer to Usart Rx transfer Buffer */
uint16_t RxXferSize; /*!< Usart Rx Transfer size */
__IO uint16_t RxXferCount; /*!< Usart Rx Transfer Counter */
DMA_HandleTypeDef *hdmatx; /*!< Usart Tx DMA Handle parameters */
DMA_HandleTypeDef *hdmarx; /*!< Usart Rx DMA Handle parameters */
HAL_LockTypeDef Lock; /*!< Locking object */
__IO HAL_USART_StateTypeDef State; /*!< Usart communication state */
__IO uint32_t ErrorCode; /*!< USART Error code */
#if (USE_HAL_USART_REGISTER_CALLBACKS == 1)
void (* TxHalfCpltCallback)(struct __USART_HandleTypeDef *husart); /*!< USART Tx Half Complete Callback */
void (* TxCpltCallback)(struct __USART_HandleTypeDef *husart); /*!< USART Tx Complete Callback */
void (* RxHalfCpltCallback)(struct __USART_HandleTypeDef *husart); /*!< USART Rx Half Complete Callback */
void (* RxCpltCallback)(struct __USART_HandleTypeDef *husart); /*!< USART Rx Complete Callback */
void (* TxRxCpltCallback)(struct __USART_HandleTypeDef *husart); /*!< USART Tx Rx Complete Callback */
void (* ErrorCallback)(struct __USART_HandleTypeDef *husart); /*!< USART Error Callback */
void (* AbortCpltCallback)(struct __USART_HandleTypeDef *husart); /*!< USART Abort Complete Callback */
void (* MspInitCallback)(struct __USART_HandleTypeDef *husart); /*!< USART Msp Init callback */
void (* MspDeInitCallback)(struct __USART_HandleTypeDef *husart); /*!< USART Msp DeInit callback */
#endif /* USE_HAL_USART_REGISTER_CALLBACKS */
} USART_HandleTypeDef;
三:重定向
如果忘记重定向了,然后还是使用了printf,程序就会卡死
当想换一个usart做端口打印的时候,只需要在重定向函数中将&huart1 换成我们需要的那个。
1:代码分析
#include <stdio.h>
///重定向c库函数printf到串口DEBUG_USART,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到串口DEBUG_USART */
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000);
return (ch);
}
///重定向c库函数scanf到串口DEBUG_USART,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
int ch;
HAL_UART_Receive(&huart1, (uint8_t *)&ch, 1, 1000);
return (ch);
}
#include <stdio.h>
//记得在usart.h中声明一下函数
/***************** 发送字符串 **********************/
void Usart_SendString(uint8_t *str)
{
unsigned int k=0;
do
{
HAL_UART_Transmit(&huart1,(uint8_t *)(str + k) ,1,1000);
k++;
} while(*(str + k)!='\0');
}
2:使用
/*调用printf函数,因为重定向了fputc,printf的内容会输出到串口*/
printf("欢迎使用野火开发板\n");
/*自定义函数方式*/
Usart_SendString( (uint8_t *)"自定义函数输出:这是一个串口中断接收回显实验\n" );
四: 轮询模式
1: HAL_USART_Transmit()
1:HAL_USART_Transmit:在规定时间内发送一个数组中的size个byte
使用这个函数的时候,可以直接用重定向中的那几个函数
2:他是没有回调函数的
// 实验1:
char a[]="这是第一句话";
uint8_t d[]="1wo\nshi";//\n也是一个字符,换行
char c=99;//这个99就代表ASCII
printf("欢迎使用开发板\n");
printf("1:%s\n",a);
Usart_SendString( (uint8_t *)"这是第二句话\n" );//这是自己定义的函数 用来发送一串的
Usart_SendString( (uint8_t *)a);
HAL_UART_Transmit(&huart1,d, 4, 1000);
HAL_UART_Transmit(&huart1, (uint8_t *)&c,1, 1000);
//实验2:
char str[80];
char num=99