STM32学习笔记06

前言

USART驱动、发送、接受、控制程序


目录

一、USART驱动程序

1、USART库函数

​二、USART发送程序

方法一:使用固件库函数

方法二:发送不同数据

方法三

三、USART接收程序

四、USART控制程序 

与终端交互


一、USART驱动程序

USART(通用同步异步收发器)是单片机内部的通信接口

在使用USART_RX和USART_TX时不能和PA9、PA10同时使用

CH340C芯片会将USB串口转换为USART串口,转换的串口为TTL电平,转换出来的接口可以直接和单片机连接,不需要外围电路。

1、USART库函数

二、USART发送程序

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);                    //使能串口 
}

void USART1_IRQHandler(void){ //串口1中断服务程序(固定的函数名不能修改)	  如电脑发来数据,就会中断跳转到此处
	u8 Res;
	//以下是字符串接收到USART1_RX_BUF[]的程序,(USART1_RX_STA&0x3FFF)是数据的长度(不包括回车)
	//当(USART1_RX_STA&0xC000)为真时表示数据接收完成,即超级终端里按下回车键。
	//在主函数里写判断if(USART1_RX_STA&0xC000),然后读USART1_RX_BUF[]数组,读到0x0d 0x0a即是结束。
	//注意在主函数处理完串口数据后,要将USART1_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){//接收未完成			
			if(USART1_RX_STA&0x4000){//接收到了0x0d				
				if(Res!=0x0a)USART1_RX_STA=0;//接收错误,重新开始
				else USART1_RX_STA|=0x8000;	//接收完成了 
			}else{ //还没收到0X0D					
				if(Res==0x0d)USART1_RX_STA|=0x4000;
				else{
					USART1_RX_BUF[USART1_RX_STA&0X3FFF]=Res ; //将收到的数据放入数组
					USART1_RX_STA++;	//数据长度计数加1
					if(USART1_RX_STA>(USART1_REC_LEN-1))USART1_RX_STA=0;//接收数据错误,重新开始接收	  
				}		 
			}
		}   		 
	} 
} 
int main (void){//主程序
	u8 a=7,b=8;
	//初始化程序
	RCC_Configuration(); //时钟设置

	USART1_Init(115200); //串口初始化(参数是波特率,即数据收发的速度,发送端和接收端要一致)

	//主循环
	while(1){

		/* 发送方法1 */
		USART_SendData(USART1 , 0x55); //发送单个数值
		while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET); //检查发送中断标志位

		/* 发送方法2 */
		printf("STM32F103 "); //纯字符串发送数据到串口
		printf("STM32 %d %d ",a,b); //纯字符串和变量发送数据到串口,a符号变量
		 
		/* 发送方法3 */
		USART1_printf("STM32 %d %d ",a,b);

        delay_ms(1000); //延时
	}
}

方法一:使用固件库函数

该函数只能发送单个数据

因为串口发送速度较快,为了防止前一个没发送下一个又开始发送,所以加一个while判断串口发送位是否为复位/置位

 

 方法一输出的16进制的数值,若输出为字符则转为相应的ASCII

DEC(十进制)HEX(十六进制)CHAR(字符)C 程序(转义)
00NUL\0
11SOH 
22STX 
33ETX 
44EOT 
55ENQ 
66ACK 
77BEL\a
88BS\b
99HT\t
100ALF\n
110BVT\v
120CFF\f
130DCR\r
140ESO 
150FSI 
1610DLE 
1711DC1 
1812DC2 
1913DC3 
2014DC4 
2115NAK 
2216SYN 
2317ETB 
2418CAN 
2519EM 
261ASUB 
271BESC 
281CFS 
291DGS 
301ERS 
311FUS 
3220space空格 
3321! 
3422" 
3523# 
3624$ 
3725% 
3826& 
3927' 
4028( 
4129) 
422A* 
432B+ 
442C, 
452D- 
462E. 
472F/ 
48~5730~390~9 
583A: 
593B; 
603C< 
613D= 
623E> 
633F? 
6440@ 
65~9041~5AA~Z 
915B[ 
925C\\\
935D] 
945E^ 
955F_ 
9660` 
97~12261~7Aa~z 
1237B{ 
1247C| 
1257D} 
1267E~ 
1277FDEL 

方法二:发送不同数据

  • %d 十进制有符号整数
  • %u 十进制无符号整数
  • %f 浮点数
  • %s 字符串
  • %c 单个字符
  • %p 指针的值
  • %e 指数形式的浮点数
  • %x, %X 无符号以十六进制表示的整数
  • %o 无符号以八进制表示的整数
  • %g 自动选择合适的表示法
  • %p 输出地址符

printf默认使用在USART1这个串口上,可以在USART.c中修改宏定义

方法三

printf同一时间只能用在一个串口上,因此我们可以自己写一个函数

void USART1_printf (char *fmt, ...){ 
	char buffer[USART1_REC_LEN+1];  // 数据长度
	u8 i = 0;	
	va_list arg_ptr;  //获取不确定个数的参数
	va_start(arg_ptr, fmt);  //arg_ptr初始化
	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);
}

va_start的事例

三、USART接收程序

单片机接收有两种:中断和查询

若用查询方式,则需要将串口中断关闭,但是其实时性较差,中断相对来说实时性较好,在收到数据后能马上跳到中断处理。

int main (void){//主程序
	u8 a;
	//初始化程序
	RCC_Configuration(); //时钟设置

	USART1_Init(115200); //串口初始化(参数是波特率)

	//主循环
	while(1){

		//查询方式接收
		if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE) != RESET){  //查询串口待处理标志位
			a =USART_ReceiveData(USART1);//读取接收到的数据
			printf("%c",a); //把收到的数据发送回电脑		  
		}
		 

//      delay_ms(1000); //延时
	}
}
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, DISABLE);//开启ENABLE/关闭DISABLE中断
    USART_Cmd(USART1, ENABLE);                    //使能串口 
}

void USART1_IRQHandler(void){ //串口1中断服务程序(固定的函数名不能修改)	
	u8 a;
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){  //接收中断(接收到的数据必须是0x0d 0x0a结尾)		
		a =USART_ReceiveData(USART1);//读取接收到的数据
		printf("%c",a); //把收到的数据发送回电脑		  
	} 
} 

中断中的判断

四、USART控制程序 

int main (void){//主程序
	u8 a;
	//初始化程序
	RCC_Configuration(); //时钟设置
	LED_Init();//LED初始化
	KEY_Init();//按键初始化
	BUZZER_Init();//蜂鸣器初始化
	USART1_Init(115200); //串口初始化(参数是波特率)

	//主循环
	while(1){

		//查询方式接收
		if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE) != RESET){  //查询串口待处理标志位
			a =USART_ReceiveData(USART1);//读取接收到的数据
			switch (a){
				case '0':
					GPIO_WriteBit(LEDPORT,LED1,(BitAction)(0)); //LED控制
					printf("%c:LED1 OFF ",a); //
					break;
				case '1':
					GPIO_WriteBit(LEDPORT,LED1,(BitAction)(1)); //LED控制
					printf("%c:LED1 ON ",a); //
					break;
				case '2':
					BUZZER_BEEP1(); //蜂鸣一声
					printf("%c:BUZZER ",a); //把收到的数据发送回电脑
					break;
				default:
					break;
			}		  
		}

		//按键控制
		if(!GPIO_ReadInputDataBit(KEYPORT,KEY1)){ //读按键接口的电平
			delay_ms(20); //延时20ms去抖动
			if(!GPIO_ReadInputDataBit(KEYPORT,KEY1)){ //读按键接口的电平
				while(!GPIO_ReadInputDataBit(KEYPORT,KEY1)); //等待按键松开 
				printf("KEY1 "); //
			}
		}		 
		if(!GPIO_ReadInputDataBit(KEYPORT,KEY2)){ //读按键接口的电平
			delay_ms(20); //延时20ms去抖动
			if(!GPIO_ReadInputDataBit(KEYPORT,KEY2)){ //读按键接口的电平
				while(!GPIO_ReadInputDataBit(KEYPORT,KEY2)); //等待按键松开 
				printf("KEY2 "); //
			}
		}		 

//      delay_ms(1000); //延时
	}
}

与终端交互

 

 

 亮度

 

USART1_RX_STA=0xC000; //初始值设为有回车的状态,即显示一次欢迎词
	while(1){
		if(USART1_RX_STA&0xC000){ //判断最高位和高位第二位是否为1,如果标志位是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");
			}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
		}

定义了全局变量

 

 USART1_RX_BUF是一个数组,可以将我们输入的多个字符记录

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){//接收未完成 判断最高位是否为1		
			if(USART1_RX_STA&0x4000){//接收到了0x0d	判断高位的第二位是否为1			
				if(Res!=0x0a)USART1_RX_STA=0;//接收错误,重新开始
				else USART1_RX_STA|=0x8000;	//接收完成了 
			}else{ //还没收到0X0D 对应ASCII是回车					
				if(Res==0x0d)USART1_RX_STA|=0x4000;  //高位的第二位置1
				else{
					USART1_RX_BUF[USART1_RX_STA&0X3FFF]=Res ; //将收到的数据放入数组
					USART1_RX_STA++;	//数据长度计数加1
					if((USART1_RX_STA&0x3fff)>(USART1_REC_LEN-1))USART1_RX_STA=0;//判断数据是否超过数组最大值,接收数据错误,重新开始接收	  
				}		 
			}
		}   		 
	} 
} 

 我的理解是,每次输入数据的回车和换行分别标记放在最高位和高位第二位,未读到这两个值时,其他值依次从0存入数组中。&按位与

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

纯合子tt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值