内部通信接口相关操作
1.1 USART发送程序
- 端口信息
2. 初始化时钟和串口
USART1_Init
void USART1_Init(u32 bound)
功能:
初始化UART相关端口
参数:
bound:波特率,600,1200,2400,4800,9600,14400,19200,115200
返回值:
无
void USART1_Init(u32 bound){ //串口1初始化并启动
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
//USART1_TX PA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
//USART1_RX PA.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
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(USART1, &USART_InitStructure); //初始化串口
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启ENABLE/关闭DISABLE中断
USART_Cmd(USART1, ENABLE); //使能串口
}
- 发送方法
- 方法1:
-
数据发送 USART_SendData
void USART_SendData(USART_TypeDef* USARTx, u8 Data)功能: 通过外设 USARTx 发送单个数据 参数: USARTx:x 可以是 1,2 或者 3,来选择 USART 外设 Data: 待发送的数据(八位十六进制) 返回值: 无 -
检查发送完成标志位状态,防止数据冲突 USART_GetFlagStatus
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, u16 USART_FLAG)功能: 检查指定的 USART 标志位设置与否 参数: USARTx:x 可以是 1,2 或者 3,来选择 USART 外设 USART_FLAG:待检查的 USART 标志位USART_FLAG_CTS CTS标志位 USART_FLAG_LBDLIN 中断检测标志位 USART_FLAG_TXE 发送数据寄存器空标志位 USART_FLAG_TC 发送完成标志位 USART_FLAG_RXNE 接收数据寄存器非空标志位 USART_FLAG_IDLE 空闲总线标志位 USART_FLAG_ORE 溢出错误标志位 USART_FLAG_NE 噪声错误标志位 USART_FLAG_FE 帧错误标志位 USART_FLAG_PE 奇偶错误标志位返回值: USART_FLAG 的新状态(SET 或者 RESET)
-
- 方法2: printf发送字符串 功能: 单一串口发送字符串,同一时间只能使用在一个串口上
- 方法3:
USART1_printf
功能:
自定义函数,多串口发送字符串,可同一时间多个串口使用
void USART1_printf (char *fmt, ...){ char buffer[USART1_REC_LEN+1]; // 数据长度 u8 i = 0; va_list arg_ptr; va_start(arg_ptr, fmt); vsnprintf(buffer, USART1_REC_LEN+1, fmt, arg_ptr); while ((i < USART1_REC_LEN) && (i < strlen(buffer))){ USART_SendData(USART1, (u8) buffer[i++]); while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); } va_end(arg_ptr); } - 相关概念
- 单引号引用ASCII码,例:'U'
- 方法1:
1.2 USART接收程序
- 初始化时钟,串口
- 查询方式接收
-
关闭串口中断
-
监控接收数据标志位的状态,为0停止接收
-
USART_GetFlagStatus
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, u16 USART_FLAG)功能: 检查指定的 USART 标志位设置与否 参数: USARTx:x 可以是 1,2 或者 3,来选择 USART 外设 USART_FLAG:待检查的 USART 标志位USART_FLAG_CTS CTS标志位 USART_FLAG_LBDLIN 中断检测标志位 USART_FLAG_TXE 发送数据寄存器空标志位 USART_FLAG_TC 发送完成标志位 USART_FLAG_RXNE 接收数据寄存器非空标志位 USART_FLAG_IDLE 空闲总线标志位 USART_FLAG_ORE 溢出错误标志位 USART_FLAG_NE 噪声错误标志位 USART_FLAG_FE 帧错误标志位 USART_FLAG_PE 奇偶错误标志位返回值: USART_FLAG 的新状态(SET 或者 RESET)
-
接收数据 USART_ReceiveData
u8 USART_ReceiveData(USART_TypeDef* USARTx)功能: 返回 USARTx 最近接收到的数据 参数: USARTx:x 可以是 1,2 或者 3,来选择 USART 外设 返回值: 接收到的字
-
- 中断方式接收(实时性高)
-
打开串口中断,串口在收到数据时跳到中断处理程序接收数据,接收完跳回主程序
-
在中断处理函数中设置接收程序
-
监控接收中断标志位的状态,为0停止接收 USART_GetITStatus
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, u16 USART_IT)功能: 检查指定的 USART 中断发生与否 参数: USARTx:x 可以是 1,2 或者 3,来选择 USART 外设 USART_IT:待检查的 USART 中断源USART_IT_PE 奇偶错误中断 USART_IT_TXE 发送中断 USART_IT_TC 发送完成中断 USART_IT_RXNE 接收中断 USART_IT_IDLE 空闲总线中断 USART_IT_LBD LIN中断探测中断 USART_IT_CTS CTS中断 USART_IT_ORE 溢出错误中断 USART_IT_NE 噪音错误中断 USART_IT_FE 帧错误中断返回值: USART_IT 的新状态(SET 或者 RESET)
-
接收数据 USART_ReceiveData
u8 USART_ReceiveData(USART_TypeDef* USARTx)功能: 返回 USARTx 最近接收到的数据 参数: USARTx:x 可以是 1,2 或者 3,来选择 USART 外设 返回值: 接收到的字
-
1.3 超级终端显示设置
-
超级终端转彩色显示 以"\033["开始以"m"结尾,以";"分隔,系统默认颜色"\033[0m"
前景 背景 颜色 30 40 黑色 31 41 紅色 32 42 綠色 33 43 黃色 34 44 藍色 35 45 紫紅色 36 46 青藍色 37 47 白色 编号 效果 0 终端默认设置(黑底白字) 1 高亮显示 4 使用下划线 5 闪烁 7 反白显示 8 不可见
1.4 超级终端串口控制程序
-
PC端控制如下菜单效果:
1y--开LED1灯 1n--关LED1灯 2y--开LED2灯 2n--关LED2灯 请输入控制指令,按回车键执行!
菜单高亮显示,白色背景,黄色前景
-
初始化时钟,LED,串口
-
初始值设为菜单界面
-
打开中断接收方式
- 判断是否接收到数据,将收到的数据发送回PC端作为显示(数据以1y,1n,2y,2n加回车0x0d和换行符0x0a结尾)
- 创建16位无符号全局变量USART1_RX_STA辅助判断接收数据状态,收到回车高二位置1,收到换行符高1位置1,收到数据值加1
- 创建数组USART1_RX_BUF[]将接收到的数据(不含回车和换行符)从第0个元素开始保存进数组
- 判断接收数据是否为回车+换行符,是则USART1_RX_STA高一高二位均置1,结束接收
-
主函数判断接收数据并做相应处理,若只收到回车加换行符打印一次选择界面
-
USART1_RX_STA函数高一二位置1,实现开机打印选择界面
//中断函数
void USART1_IRQHandler(void){ //串口1中断服务程序(固定的函数名不能修改)
u8 Res;
//以下是字符串接收到USART_RX_BUF[]的程序,(USART_RX_STA&0x3FFF)是数据的长度(不包括回车)
//当(USART_RX_STA&0xC000)为真时表示数据接收完成,即超级终端里按下回车键。
//在主函数里写判断if(USART_RX_STA&0xC000),然后读USART_RX_BUF[]数组,读到0x0d 0x0a即是结束。
//注意在主函数处理完串口数据后,要将USART_RX_STA清0
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){ //接收中断(接收到的数据必须是0x0d 0x0a结尾)
Res =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
printf("%c",Res); //把收到的数据以 a符号变量 发送回电脑
if((USART1_RX_STA&0x8000)==0){//判断USART1_RX_STA高一位是不是1
if(USART1_RX_STA&0x4000){//判断USART1_RX_STA高二位是不是1
if(Res!=0x0a)USART1_RX_STA=0;//判断接收值Res不是换行符,USART1_RX_STA置零,接收错误重新开始
else USART1_RX_STA|=0x8000; //判断接收值Res是换行符USART1_RX_STA高一,二位置1,接收完成
}
else{
if(Res==0x0d)USART1_RX_STA|=0x4000;//判断接收值Res是回车,USART1_RX_STA高二位置1
else{//判断接收值Res不是回车
USART1_RX_BUF[USART1_RX_STA&0X3FFF]=Res ; //将接收值Res放入数组第USART1_RX_STA&0X3FFF位
USART1_RX_STA++; //USART1_RX_STA数据长度计数加1
if(USART1_RX_STA>(USART1_REC_LEN-1))USART1_RX_STA=0;//接收数据超过BUF长度,USART1_RX_STA置0重新开始接收
}}}}}
//主函数:
while(1){
if(USART1_RX_STA&0xC000){ //如果标志位是0xC000表示收到数据串完成,可以处理。
if((USART1_RX_STA&0x3FFF)==0){ //单独的回车键再显示一次欢迎词
printf("\033[1;47;33m\r\n"); //设置颜色(参考超级终端使用)
printf(" 1y--开LED1灯 1n--关LED1灯 \r\n");
printf(" 2y--开LED2灯 2n--关LED2灯 \r\n");
printf(" 请输入控制指令,按回车键执行! \033[0m\r\n");
}else if((USART1_RX_STA&0x3FFF)==2 && USART1_RX_BUF[0]=='1' && USART1_RX_BUF[1]=='y'){ //判断数据是不是2个,第一个数据是不是“1”,第二个是不是“y”
GPIO_SetBits(LEDPORT,LED1); //LED灯都为高电平(1)
printf("1y -- LED1灯已经点亮!\r\n"444441);
}else if((USART1_RX_STA&0x3FFF)==2 && USART1_RX_BUF[0]=='1' && USART1_RX_BUF[1]=='n'){
GPIO_ResetBits(LEDPORT,LED1); ////LED灯都为低电平(0)
printf("1n -- LED1灯已经熄灭!\r\n");
}else if((USART1_RX_STA&0x3FFF)==2 && USART1_RX_BUF[0]=='2' && USART1_RX_BUF[1]=='y'){
GPIO_SetBits(LEDPORT,LED2); //LED灯都为高电平(1)
printf("2y -- LED2灯已经点亮!\r\n");
}else if((USART1_RX_STA&0x3FFF)==2 && USART1_RX_BUF[0]=='2' && USART1_RX_BUF[1]=='n'){
GPIO_ResetBits(LEDPORT,LED2); ////LED灯都为低电平(0)
printf("2n -- LED2灯已经熄灭!\r\n");
}else{ //如果以上都不是,即是错误的指令。
printf("指令错误!\r\n");
}
USART1_RX_STA=0; //将串口数据标志位清0
}
}
- 相关概念
- 全局变量extern 全局变量在函数任意位置都可以调用,但是固定占用RAM空间不宜过多使用,在.c文件定义全局变量,在.h文件extern声明即可使用
- 位运算:
- &按位与 两个位都为1时,结果才为1
- |按位或 两个位都为0时,结果才为0
- ~按位取反 两个位相同为0,相异为1
- ^按位异或 0变1,1变0
- << 左移 各二进位全部左移若干位,高位丢弃,低位补0
- >> 右移 各二进位全部右移若干位,对无符号数,高位补0,有符号数,右移补1