USART
配置USART需要添加usart.c和misc.c函数。
一、USART配置
由图可知,USART1和USART2所用的IO口分别是PA9、PA10、PA2、PA3。
- 配置IO初始化结构体、中断初始化结构体、串口初始化结构体。
- 使能所用串口和IO口所在总线的时钟。
- IO口配置注意:RX的引脚功能为浮空输入,TX的引脚功能为复用推挽输出。
- 中断配置注意:中断源为所用的串口中断源,在stm32f10x.h中。
- 串口配置注意:配置所用的波特率、串口的工作模式(RX、TX)、发送的数据位(8位)、停止位(1位)、奇偶校验位(无)、硬件控制流(不使用)。
- 使能所用串口,使能所用的串口接收中断。
void USART2_Init(u32 baud) //输入参数:波特率
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); //中文参考手册2.1系统架构
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //TX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //RX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = baud;
USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;
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_Init(USART2, &USART_InitStructure);
USART_Cmd(USART2, ENABLE);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
}
二、字符串发送函数
库函数usart.c自带的发送字函数是u16类型的,我们在编写发送字符串函数时,可以将字符串的类型改为u8或char发送的就是8位的数据。
STM32发送数据是一个一个字节发送,因此每发送一个字节的数据后要等待发送缓冲为空,才能继续发送下一个数据,即while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);当没有发送完成,发送缓冲区就一直为非空状态标志位为0,一直等待该字节发送完成后标志位为1,跳出while。
发送的数据要带结束标志符号或直接用’\0’。
void USART2_SendString(u8 *str)
{
u8 index = 0;
while(str[index] != '\0')
{
USART_SendData(USART2, str[index]);
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); //等待数据发送完成,发送完成为SET = 1
index ++;
}
}
三、USART中断函数中接受字符串
在中断函数里面,我们判断RXNE(接收)中断标志位是否被置1,如果接收中断标志位被置1,则代表产生了接收中断,可以开始执行中断里的内容,并清除RXNE中断标志位,使用USART_ClearITPendingBit函数进行清除。
通过结束符号判断接收的字符串有效位数。
u8 RXBUF[20];
u8 flag = 0;
u8 num = 0;
void USART2_IRQHandler(void)
{
u8 temp;
if(USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
{
USART_ClearITPendingBit(USART2, USART_IT_RXNE);
temp = USART_ReceiveData(USART2);
if(temp == '.')
{
flag = 1;
}
if(flag == 0)
{
RXBUF[num] = temp;
num ++;
}
}
}
其中‘.’为字符串结束符号。
四、字符串数组赋数字零
在字符串数组定义时一般不会进行赋初值,里面的内容为空。给字符串赋数字零,在ASCII码里对应的是NULL在LCD上不会显示,相当于对字符串数组初始化。
五、USART_ASCII实验
1. 实验目标
设计一个单片机程序,通过串口ASCII码表
基础完成要求:
(1) 熟练使用串口通信的接口
(2) 选择合适的波特兰进行串口通信
(3) 将ASCII码表进行编码
(4) 传输英语新概念2的第一课课文到另外一个单片机上
2. 实验方案
只是用一个单片机,由USART1发送数据,USART2接收数据,将接收的数据显示在LCD屏上。
LCD屏一次只能显示200个字符,按键1进行数据发送和第一次显示,按键2控制显示内容一次新显示100个字符。
编码方式:位操作,因为数据在单片机内用二进制进行存储,要发送的字符通过for查表得到十进制的ASCII码,和0x80相与得到左边第一位的二进制编码,循环8次左移7次,每次判断出一位二进制发送一位。
解码方式:位操作,判断每次接收数据是‘0’还是‘1’,u8类型的每次分别左移一位加0或1,当进行8次后,查表,找到表中对应的字符。
3. 相应代码
(1)串口初始化:接收数据时需要使用串口中断,所以只需要配置和使能USART2的中断。
(2)ASCII编码
注意数据存储的类型不同,但是在单片机内部均是由二进制存储的。因此通过查表得到字符所在位置后可以通过for循环和位操作得到该字符二进制编码的每一位。
(3)在串口中断中进行解码
(4)LCD全屏显示函数
在行显示的基础上加一个循环即可。
(5)主函数中翻页(每次按键按下后只更新半屏)
(6)实验效果
4. 扩展:用格雷码进行编码
方法一:更改ascii表
上图为格雷码的编码表,第127的编码为0100 0000,为64,即在ASCII码表中为@,所以需要把ASCII表中127的位置改为@即可,一次类推。
方法二:
二进制码->格雷码(编码):从左位第二位起,依次将每一位与左边一位异或(XOR),作为对应格雷码在该位的值,最左边一位不变;
格雷码->二进制码(解码):从左边第二位起,将每位与左边一位解码后的值异或,作为该位解码后的值(最左边一位依然不变)。
(以上仅个人观点)