在本次实验中,我们运行该实验内容为通过IIC总线读取温湿度传感器(SHT30)数值并串口打印显示,实验大致过程描述为如下:
我们由STM32向温湿度传感器SHT30发送相关指令,由STM32通过IIC总线接收温湿度传感器的相关数值,再将该数据经过相关公式的转变计算,形成具体的温度与湿度数值,再经由串口UART1发送至电脑的XCOM串口调试助手或者经由串口UART2发送至蓝牙模块,再由串口传输至PC端串口调试助手XCOM进行温湿度的实时显示。如下为具体相关说明:首先,我们在HARDWARE文件夹下建立uart.c与uart.h作为串口处理函数块的头文件与源文件、在HARDWARE文件下建立sht30.c与sht30.h作为温湿度传感器的数值读取函数块的头文件与源文件。在外围文件中分别新建UART文件夹与HARDWARE文件夹用来存放uart.c与uart.h、sht30.c与sht30.h。存放好以后,我们分别将uart.c与sht30.c引入HARDWARE框架之下,操作如下图所指示:
然后点击魔术棒,在C/C++选项卡中引入头文件所在路径,使我们的编译器可以识别头文件所在位置。如下图所示:
这些准备工作做好以后,接下来可以分别编写4个头文件与源文件了,首先,编写uart.h串口的头文件,即如果没有定义,则新定义uart.h头文件。在该头文件中,声明我们源文件中所编写好的串口初始化函数。在此我们初始化并设置串口1连接XCOM的相关参数。
在编写好头文件后,接下来我们其对应编写源文件uart.c,首先我们需要该源文件中将所用到的全部头文件都引入进来,如下图所示。
其次我们编写串口uart1的初始化函数,在该uart1_Init函数中调用串口的初始化函数并设置相关参数,蓝牙串口波特率为115200,其次编写MspInit弱函数,并在该函数中对串口uart1和对应的GPIO口进行时钟使能并调用函数对串口对应的GPIO口进行初始化。到此,我们就完成了源文件uart.c与头文件uart.h的编写,接下来,我们编写读取温湿度数值的sht30.c与sht30.h文件。与上面一样,首先编写sht30.c源文件,与前面一样,定义头文件,在该头文件中,我们将后面.c文件中用到的函数即变量均在此进行声明。详细代码文件如下图所示。
接下来,我们讨论编写源文件相关函数体,并且此处也为整个实验的关键部分。首先,需要将我们在该源文件中用到的头文件全部引入进来,如下图所示。
然后,我们在函数体中实现对温湿度传感器数值的读取,首先编写读取一次数据的代码,每调用一次IIC的读取函数,即读出一字节(8位)数据,,我们需要循环读取6次分别获得温度的高位、温度的低位、校验位、湿度的高位、湿度的低位、校验位。这个过程都包含在了温湿度传感器的芯片手册上了,具体的详细读取过程我们也需要非常仔细地去研究sht30温湿度传感器所对应的芯片手册,来获取相关信息。详细的重要时序图如下图所示。具体读取过程按照我们时序图大致描述为如下:首先发送开始信号,接着发送写模式(该写模式为8位数据组合,前7位为芯片手册中所说的0x44,最后一位为读写标志位,写为0,读为1,由时序图知,先发送写信号,然后发送等待应答信号,接着发送高8位数据,然后发送等待应答信号,接着再发送低8位数据,然后发送等待应答信号),最后发送停止信号。准备工作做好后,接着我们来将时钟线拉高,准备读取数据,此时发送时钟高电平,因为时序图中标注该时钟拉高后,正在读取数据,故此处需要延时等待,接着发送开始信号,再发送8位读模式(读模式为发送0x89,也就是七位0x44数据后面再加最后一位读位1)。接着再发送等待应答信号。到此为止,主机的相关设置基本结束,接下来就开始6次接收数据,将其放置于循环中,在循环体内部判断,由于我们要接收6次数据,其中前5次接收需要返回应答信号,最后一次需要返回非应答信号。所以我们在循环体内部判断数据是否小于5,如果小于5,即前五次应答信号ack为1,在下面调用读取数据函数时ack自然为1,自然会返回应答信号。否则应答信号为0,在下面读取数据函数后,ack为0时,自然会返回非应答信号。以此来完成数据的读取,当数据读取结束后,将数据保存至我们定义好的数组中。
当编写完读取一次数据代码后,我们已经将读取来的数值存入了一个数组中,在我们本实验中,存放于数组p中。接下来我们再编写读取到数值后的具体处理程序,即voidSHT30_Getdata(void)函数,在该函数中,我们将读取来的数据进行公式计算转换为温湿度值,但是该温湿度值为浮点型数据,我们想要将该温湿度值经由Transmit函数发送至XCOM(经由uart1发送),只能变为整数型的数据,才能进行发送,所以我们需要将浮点型数据转换为整形数据,使用函数sprintf来转换,转换结束以后将温湿度数值发送至串口,由串口发送至电脑XCOM调试助手进行显示。详细代码块如下图所示。【注:代码中应是串口uart1】
上面,我们通过编写两个函数,一个作为具体的读取数据过程的函数,另外一个作为对读取出来的数据进行加工处理的函数。上面我们已经对读取温湿度值的函数(即第一个函数)进行了详细的说明。接下来,我们对读取数值进行数据处理的函数块进行说明,如上图中使用箭头进行标注的:
(1)(2)该函数即为具体的读取温湿度传感器数据的过程
(3)在此处,我们定义两个数组,分别是p和a,其中数组p[6]存放温湿度数据,分别存放温度的高位、温度的低位、温度校验位、湿度的高位、湿度的低位以及湿度校验位。其中a[100]用来存放将温湿度高低位经过公式计算后的数据。
(4)memset函数的说明:作用是将某一块内存中的内容全部设置为指定的值,这个函数通常为新申请的内存做初始化工作。该完整函数为void *memset(void *s, int ch, size_t n);上述函数的作用为:将s中当前位置后面的n个字节(typedefunsigned int size_t )用ch 替换并返回s,该函数的作用是在一段内存块中填充某个给定的值,它是对较大的
结构体
或
数组
进行清零操作的一种最快方法。在我们的函数memset(a,0x00,100);中,代表将数组a中当前开始的100个值均清为0,相当于数组的初始化函数。
(5)通过公式处理读取来的高位以及低位,将高位与低位合并处理合为正数,具体处理过程如下图所示。
(6)关于sprintf(a,"%fC %f %%\r\n",Tem_Value,RH_Value);函数。因为我们有我们读取来的温湿度值均为浮点型数据,但是我们接下想要经由串口发送,串口只能发送整形类数组数据,所以我们需将读取来的浮点型数据格式进行转化,这就使用到了上述函数,sprintf指的是字符串格式化命令,函数声明为 int sprintf(char*string, char *format [,argument,...]);,主要功能是把格式化的数据写入某个字符串中,即发送格式化输出 string所指向的字符串。sprintf是个变参函数。使用sprintf 对于写入buffer的字符数是没有限制的,这就存在了buffer溢出的可能性。解决这个问题,可以考虑使用 snprintf函数,该函数可对写入字符数做出限制。
在我们本函数中sprintf(a,"%f C %f%%\r\n",Tem_Value,RH_Value);含义为,将Tem_Value的值对应到前面的%f,后面跟着输出C,将RH_Value的值对应到前面的%f,后面跟着输出%(注:%%为输出%这个符号,即印出百分比的符号)。将转换的结果(温度和湿度)值存放于数组a当中。并在其后进行/r/n回车换行输出。
(7)在我们将所有数据取出来、进行高低位合成、使用公式计算温湿度值、存放于数组中、改变数据格式存放于数组中后,我们就将这些数据通过串口uart1发送至PC端调试助手XCOM,通过串口发送使用Transmit函数来进行。 上面将本实验的核心代码编写完成,接下来我们只需要在主函数中对所编写的函数进行直接调用使用即可。主函数代码大致描述为如下:首先将主函数中使用到函数所在的头文件都包含进来,并在其下方调用各初始化函数进行LED小灯、XCOM对应串口uart1以及所用到的IIC总线驱动的初始化。如下图所示:
如上图所示,在主函数中对LED小灯进行玩耍,使其进行循环闪烁,与本次实验无关系。在下面调用读取处理并打印的函数SHT30_Getdata();进行显示。完成以上全部流程后,我们将代码下载至板子,打开电脑上串口调试助手XCOM进行数据的实时显示结果界面如下图所示。
图/LY
文/LY