1.物理层
1.1电平标准
通常有TTL和RS232电平标准
2.协议层
2.1数据包
通常由起始位、8位数据位、校验位、停止位,一共11位。
2.2波特率
我们经常使用的是Uart也就是异步通讯,因为没有时钟线连接,所以需要约定好单位时间内发送的数据量。 通常使用9600、115200
3.实现目标:单片机串口收发
3.0串口配置
这里使用串口5,即UART5
void uart5_init(u32 bps)
{
NVIC_InitTypeDef NVIC_InitStruct;
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5, ENABLE);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_5);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_5);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStruct.NVIC_IRQChannel = UART5_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 4;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
USART_InitStructure.USART_BaudRate = bps;
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(UART5, &USART_InitStructure);
USART_Cmd(UART5, ENABLE);
}
初始化配置,多使用几遍就会熟悉,大家不要害怕。
3.1串口发送
3.1.1串口发送单字符
void Usart_SendByte(USART_TypeDef *pUSARTx,uint8_t dat)
{
USART_SendData(pUSARTx,dat);
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE)!=SET);
}
代码分析
在STM32F30xx_usart.h标准库函数中定义USART_SendData()
发送数据,即对DR寄存器进行写操作
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
{
assert_param(IS_USART_ALL_PERIPH(USARTx));
assert_param(IS_USART_DATA(Data));
USARTx->TDR = (Data & (uint16_t)0x01FF);
}
通过数据寄存器DR进行发送数据,寄存器大小[31:0],规定数据位[8:0],一共9位,所以当对TDR进行写操作时 USARTx->TDR = (Data & (uint16_t)0x01FF); 数据寄存器是包含了TDR(发送)和RDR(接收)两个寄存器, 当我们对DR(数据寄存器)写操作就是发送,读操作就是接收
接收数据,即对DR寄存器进行读操作
uint16_t USART_ReceiveData(USART_TypeDef* USARTx)
{
assert_param(IS_USART_ALL_PERIPH(USARTx));
return (uint16_t)(USARTx->RDR & (uint16_t)0x01FF);
}
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE)!=SET);
在STM32F30xx_usart.h标准库函数中定义USART_GetFlagStatus()
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint32_t USART_FLAG)
{
FlagStatus bitstatus = RESET;
assert_param(IS_USART_ALL_PERIPH(USARTx));
assert_param(IS_USART_FLAG(USART_FLAG));
if ((USARTx->ISR & USART_FLAG) != (uint16_t)RESET)
{
bitstatus = SET;
}
else
{
bitstatus = RESET;
}
return bitstatus;
}
单字符发送完成时,即数据已经从TDR寄存器传输到移位寄存器时,USART_TXE标志位置1,USART_GetFlagStatus函数返回SET。
3.1.2 串口发送字符串
void Usart_SendByte1(USART_TypeDef *pUSARTx, char *str)
{
uint8_t i=0;
do{
Usart_SendBit(pUSARTx,*(str+i));
i++;
}while(*(str+i)!='\0');
}
void Usart_SendByte2(USART_TypeDef *pUSARTx,uint8_t *str)
{
uint8_t i=0;
do{
Usart_SendBit(pUSARTx,str[i]);
i++;
}while(str[i]!=0);
}
上面的两种写法说明了一点,char字符串在存储方式类似于字符数组,因为他们都具有可以单独取出一串中的其中一个。
字符串使用指针自增访问每一个子串。 字符数组通过数组位号访问每一个字符。
main.c
int main(void)
{
SystemCoreClockUpdate();
SysTickInit();
uart5_init(115200);
uint8_t test[] = "这是字符串写法2的输出\r\n";
Usart_SendByte1(UART5,"这是字符串写法1的输出\r\n");
Usart_SendByte2(UART5,test);
while()
{
}
}
发送结果
3.2串口接收
前面配置串口的时候已经使能了串口接收中断,通过 USART_ITConfig(USART_TypeDef* USARTx, uint32_t USART_IT, FunctionalState NewState)
三个参数,串口号,串口中断类型,开启或关闭
使用例
USART_ITConfig(UART5,USART_IT_RXNE,ENABLE);
通过UART5句柄函数,当发生接收中断时,将数据使用USART_SendData()函数返还到串口5TDR寄存器发送出去。
void UART5_IRQHandler(void)
{
uint16_t temp;
if(USART_GetFlagStatus(UART5,USART_IT_RXNE)!=RESET)
{
temp = USART_ReceiveData(UART5);
USART_SendData(UART5,temp);
}
}
接收函数USART_ReceiveData()和发送函数USART_SendData()的详情前面已经贴出来了,任然感觉不清楚可以返回前面再看看。
接收结果
|