最近为了配置一个芯片使用到了串口发送9位数据位的情况,在此小记一下。
1. 串口硬件和参数初始化
将数据位宽度配置成:UART_WORDLENGTH_9B
,其他参数和常规配置一样。
UART_HandleTypeDef husart3;
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(huart->Instance==USART3)
{
__HAL_RCC_GPIOC_CLK_ENABLE();//IO时钟使能
GPIO_InitStruct.Pin = USARTx_Tx_GPIO_PIN|USARTx_Rx_GPIO_PIN;//PB10和PB11
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = USARTx_AFx;
HAL_GPIO_Init(USARTx_Tx_GPIO, &GPIO_InitStruct);
GPIO_InitStruct.Pin = USARTx_Rx_GPIO_PIN;
HAL_GPIO_Init(USARTx_Rx_GPIO, &GPIO_InitStruct);
}
}
void MX_USART3_Init(void)
{
__HAL_RCC_USART3_CLK_ENABLE();//串口3时钟使能
huart3.Instance = USART3;
huart3.Init.BaudRate = USART3_BAUDRATE;
huart3.Init.WordLength = UART_WORDLENGTH_9B;//数据位宽度改为9位
huart3.Init.StopBits = UART_STOPBITS_1;//一位停止位
huart3.Init.Parity = UART_PARITY_NONE;//无奇偶校验位
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart3);
HAL_UART_Receive_IT(&huart3,Usart3_TempData,1);
HAL_NVIC_SetPriority(USART3_IRQn, 2, 2);
HAL_NVIC_EnableIRQ(USART3_IRQn);
}
2. 串口发送相关库函数的修改
看了下库函数,如果想要收发数据位宽度为9位的数据,貌似只能够通过阻塞模式发送,如下是阻塞模式下串口发送数据的库函数(省略部分函数,只留取了最关键的代码):
/**
* @brief Sends an amount of data in blocking mode.
* @param huart: pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param pData: Pointer to data buffer
* @param Size: Amount of data to be sent
* @param Timeout: Timeout duration
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
...省略
if(huart->Init.WordLength == UART_WORDLENGTH_9B)
{
...省略
tmp = (uint16_t*) pData;
huart->Instance->DR = (*tmp & (uint16_t)0x01FF);
...省略
}
...省略
}
我发现这个库函数发送数据宽度为9位数据时时这样的,如果第9位数据为0的话,本质就是在停止位前添加一位数据0,如果第九位想发1的话,那就不需要这个函数了,即通过正常的8N1格式发送即可,直接用停止位当第9位就可以.
这样的话是可以实现,只是比较麻烦。比如在使用9位数据宽度配置一些传感器时需要反复的将第9位变为1或0,如果按照官方提供的这种库函数来实现的话,那就得反复将串口配置成8B或9B的模式,非常的不方便,也很不直观。所以我把这个函数做了一些简单的修改,多加了一个第9位位选择的参数。
程序如下:
/**
* @brief Sends an amount of data in blocking mode.
* @param huart: pointer to a UART_HandleTypeDef structure that contains
* the configuration information for the specified UART module.
* @param pData: Pointer to data buffer
* @param Size: Amount of data to be sent
* @param Bit_9 : bit 9 state
* @param Timeout: Timeout duration
* @retval HAL status
*/
HAL_StatusTypeDef HAL_UART_Transmit_9B(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint8_t Bit_9, uint32_t Timeout)
{
...省略
if(huart->Init.WordLength == UART_WORDLENGTH_9B)
{
...省略
tmp = (uint16_t*) pData;
//huart->Instance->DR = (*tmp & (uint16_t)0x01FF);之前的数据处理方式屏蔽掉
//以下是自己添加的第九位数据位处理的相关代码
if(Bit_9 == 1)
{
huart->Instance->DR = (*tmp | (uint16_t)0x0100);//将第九位置1
}
else
{
huart->Instance->DR = (*tmp & (uint16_t)0x00FF);//将第九位置0
}
...省略
}
...省略
}
提示:最后就是记得在头文件中声明该函数!