实验一:
工程。

链接:https://pan.baidu.com/s/1g8DV4yZWOix0BbcZ08LYDQ?pwd=2176 
提取码:2176
  • 1.
  • 2.

407串口01发送_串口

串口1的使用。发送功能。
单片机发送信息到电脑。
通过串口进行通信。

首先单片机这边。
单片机这边,需要对单片机的串口模块进行使能初始化,设置串口的格式。
单片机和电脑的串口收发格式要配置一致。不然A和B肯定通信不成功,鸡和鸭讲,对牛弹琴。

打开串口助手,看下格式。

格式包括波特率,停止位,数据位和校验位。电脑端的串口助手(我们这里使用XCOM的串口助手)默认这个配置,单片机也这么配置一下。

407串口01发送_串口_02

407串口01发送_初始化_03


407串口01发送_单片机_04


407串口01发送_单片机_05

407串口01发送_单片机_06


407串口01发送_单片机_07

看到上述的串口初始化的步骤主要是
1、初始化端口的时钟,串口1的时钟,都要打开,因为我们需要用到芯片的该个功能,因此必须打开对应时钟。
2、由于端口PA9和PA10默认是IO模式,这个我们配置为端口复用模式,切换到串口1功能;
3、串口1的具体格式的初始化。设置通信格式,和要通话端的格式一致。
4、使能串口,清空串口对应的中断标记位。允许发生中断。
5、在其他地方或者这个函数里面,我们可以设置串口1的中断优先级等,配置一下。这里在前面配置了。

407串口01发送_串口_08

407串口01发送_串口_09

初始化函数用PA9和PA10作为串口使用。

可以用stm32CubeMX软件查看。

如何对stm32查看IO功能。-CSDN博客

407串口01发送_初始化_10


407串口01发送_初始化_11

看到PA9和PA10分别是串口1的TXD发送和RXD接收引脚。

这里我们需要用到一个USB-TTL模块,我们可以自学习一下232电平,TTL电平等。记得发送和接收对接。才能正常收发数据。

407串口01发送_初始化_12

这里我们只是对发送功能进行讲解,因此接收的中断先不讲解。

使用这个的时候,先在工程中确认包括usart.c文件。然后用里面的额初始化函数进行初始化。注意波特率。
然后再main.c中的main函数里面,进行include头文件,然后进行串口初始化。

这里讲解一下printf函数。printf函数,我们一般在一开始学习C语言的时候,就讲解了。那时候我们是将printf函数输出到电脑的屏幕中,查看一下信息,比如变量,字符串啊等等信息。这里我们用printf函数,也是实现这个功能。

不过单片机里面执行printf函数,需要多一个重定向的步骤。告诉单片机,我们需要在单片机的那个串口printf出去,要重定向到对应的单片机串口才行。

407串口01发送_初始化_13

所以在usart.c文件里面。看到这个函数里面有串口1,因为我们的PA9和PA10就是串口1,定向到这个,我们的串口才能输出信息打印出去。

你可以配置串口3,然后这里改为串口3,那么printf就定向到串口3去了,同理也一样。

407串口01发送_串口_14

我们可以修改一下这个函数,改为大写的Printf函数,或者多一个函数的形参,后面我们再讲解。

在库中的stm32f4xx_usart.c中,包括了一个发送字节,一个是接收字节的函数。这是库函数的东西,主要是将缓冲区的数据读取出来或者是发送出去。

在这个函数基础上,我们在sys.c中添加3个函数,一个是发字节,一个是发字符串,一个是自定义大写的Printf函数。注意在sys.h中要添加对应函数的声明。
//**********************************************************************
// /* 发送一个字节数据到USART */

void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
	/* 发送一个字节数据到USART */
	USART_SendData(pUSARTx,ch);	
	/* 等待发送数据寄存器为空 */
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);	
		
//	while((pUSARTx->SR&0X40)==0);//循环发送,直到发送完毕   
//			pUSARTx->DR = (u8) ch;   
//	
}

//*******************************************************************
  //字符串发送函数
void Usart_SendString( USART_TypeDef * pUSARTx,char *buffertemp)		
{
	uint8_t i=0;
	while(1)
	{
	 if(buffertemp[i]!='\0')
	 {
			USART_SendData(pUSARTx,buffertemp[i]);  //发送一个字节
			while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TXE)==RESET){};//等待发送结束
		 	i++;
	 }
	 else 
	   return ;
 
	}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.

/*

/*


  • 函 数 名: Printf
  • 功能说明: 可变参数重定义Printf函数
  • 形 参: 1.串口号 2.char* fmt,… 格式化输出字符串和参数
  • 返 回 值: 无

*/

#define    USART_SENDBUFFLEN     256          //定义打印的字符串数组长度

char g_USART_SendBuff[USART_SENDBUFFLEN];     //用于打印的字符串数组

void Printf(USART_TypeDef* USARTx, char* fmt, ...)
{
   
    u16 i = 0;  		
	  va_list ap;                                  //清空下标
	  memset(g_USART_SendBuff,0,USART_SENDBUFFLEN); //清空字符数组
    //可变参数列表变量(对象)
		va_start(ap,fmt);                         //指明char*类型的fmt参数后面的才是可变参数的开始
		vsprintf(g_USART_SendBuff,fmt,ap);        //使用参数列表发送格式化输出到字符串
		va_end(ap);	                              //清空参数列表变量(对象)

	  while(g_USART_SendBuff[i])                //如果字符串数组为NULL则退出打印
		{
		  while((USARTx->SR&0X40)==0);
		  USARTx->DR = g_USART_SendBuff[i++];
		}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

这里可以把这个USART_SENDBUFFLEN改为100,一般发送不会发送太多数据,100个字节基本够用了。

在SYS.h中添加对应的函数声明。

准备步骤充分了,我们就可以使用里面的函数,发送信息。

注意串口4和串口5是没有S的,少了一个字母。具体可以自己在学习。

407串口01发送_初始化_15


实验记录和分析

从下图看到。发字母a,我们用十六进制接收显示,得到的是0x61,0x在串口助手不显示。

数字1,得到的是0x01;

数字200,得到的是0xC8;

字母b,接收的是0x62;

发送十六进制0x0d,接收得到0x0d;

发送十六进制0x0a,接收的是0x0a。

407串口01发送_串口_16


为什么发送的是字母小写的a,接收得到的是0x61呢。

首先我们再学习一下ascii码。

在计算机中,所有的数据在存储和运算时都要使用二进制数表示(因为计算机用高电平和低电平分别表示1和0),例如,像a、b、c、d这样的52个字母(包括大写)以及0、1等数字还有一些常用的符号(例如*、#、@等)在计算机中存储时也要使用二进制数来表示,而具体用哪些二进制数字表示哪个符号,当然每个人都可以约定自己的一套(这就叫编码),而大家如果要想互相通信而不造成混乱,那么大家就必须使用相同的编码规则,于是美国有关的标准化组织就出台了ASCII编码,统一规定了上述常用符号用哪些二进制数来表示 [2]。

美国信息交换标准代码是由美国国家标准学会(American National Standard Institute , ANSI )制定的,是一种标准的单字节字符编码方案,用于基于文本的数据。它最初是美国国家标准,供不同计算机在相互通信时用作共同遵守的西文字符编码标准,后来它被国际标准化组织(International Organization for Standardization, ISO)定为国际标准,称为ISO 646标准。适用于所有拉丁文字字母 [3]。我们查一下ascii码表。

https://www.runoob.com/w3cnote/ascii.html

407串口01发送_初始化_17


可以看到我们单片机发送的小写字母a,电脑或者另外一个设备接收到,也是字母a,不过用十六进制是0x61。

我们发送数字1给电脑,数字1用十六进制表示,也是0x01,因此电脑这边接收到之后,用十六表示也是0x01.

我们发送数字200给电脑,单片机将200实际也是底层用二进制编码的,转十六进制格式。

因此电脑这边用十六进制显示也是0xC8。一样。

407串口01发送_串口_18


所以我们要明白

两个电子设备通信,基本都是0和1的通信。

0和1组合起来的格式编码起来,一般用ascii码,能显示就是显示字符,不能的就是不可显示,有一些是控制字符。

不管我们发的是字母,数字,都是转为十六进制转为二进制发送出去。

接收这边,收到0和1,如果编码格式一样,那么就同样解码,不一样,就要额外做点手段解码。