本文为物联网温度采集系统底层感知网络搭建的一些项目经验分享,主要包括了Altium Designer 17、Keil uVision5等开发软件的使用,以及初期调试所需注意的一些问题。本系统选用STM32F103C8T6芯片作为核心控制器,温度芯片选用TMP275-Q1,采用WIFI模块进行数据传输。初期调试采用预留串口及外接OLED屏进行交互。
Abstract:
This article shares some project experience sharing for the underlying sensing network of the IoT temperature acquisition system, including the use of development software such as Altium Designer 17, Keil uVision5, and some issues that need attention during initial debugging. This system selects STM32F103C8T6 chip as the core controller, temperature chip selects TMP275-Q1, data transmission adopts WIFI module. The initial debugging uses a reserved serial port and an external OLED screen for data interaction.
想要制作一个物联网系统,底层感知网络的搭建是必不可少的,此次我们选用ARM公司的STM32F103C8T6作为主控芯片、TI公司的TMP275-Q1 作为传感器芯片搭建小系统版。小系统的电路设计采用的是AD17,AD17作为一款较成熟的制图软件,无论是在操作上还是开发上都有很多可圈可点之处,而且它的查错功能对后期板子开出来的可行性也提供了很好的保障。当然,这个过程千万不要忘了查找各个模块的数据手册,查清各个引脚的定义。
(下面放出主要的原理图和pcb图)
搭建完小系统版后,好戏才刚刚开始,这个时候我们需要给他注入一点“生机”,让它能够自己把温度采集上来并发到服务器上去。这些功能我们通过C语言实现,用Keil uVision5进行编程烧写。
整体工程代码文件如下:
32作为库函数编程的典例,充分地展示了库函数编程的方便。而且由于是用C语言进行编程,其执行效率也是很可观的。搭建一个32工程就好比玩沙盘测试,所有的模块已经帮你准备好了,你只需要按照你的想法进行搭建就完事了。
(话不多说,上代码)
/*主函数代码*/
#include "stm32f10x.h"
#include "usart2.h"
#include "usart3.h"
#include "myiic.h"
#include "delay.h"
#include "tmp275.h"
#include "wifi.h"
#include "oled.h"
int num;
int number;
float i;
char crc[20];
char str[200];
char end[200];
char data[200];
char crc_reg[20];
char Temp_Result[20];
int main(void)
{
TMP275_Init();
delay_init();
Usart2_Init(9600);
Usart3_Init(115200);
WiFi_ResetIO_Init();
OLED_Init();
OLED_Clear();
while(1)
{
OLED_ShowString(0,5,(u8*)"Connecting");
if(Connect_flag==1)
{
TMP275_Read_Registers(0X00);
i = TMP275_Get_Temp();//读温度
sprintf(Temp_Result,"%.1f",i);//温度转字符串
memset(data,0,sizeof(data));//清空
sprintf(data,"%s%s%s%s;",ST,MN,Temp_Head,Temp_Result);//数据段组合
number=strlen(data);//计算数据段长度
if(number>=1&&number<10)
{
sprintf(str,"000%d",number);//补齐4位数据段
}
else if(number>=10&&number<100)
{
sprintf(str,"00%d",number);
}
else if(number>=100&&number<1000)
{
sprintf(str,"0%d",number);
}
else if(number>=1000&&number<10000)
{
sprintf(str,"%d",number);
}
else
{
u2_printf("数据段错误");
}
memset(crc_reg,0,sizeof(crc_reg));//清空
sprintf(crc_reg,"%X",CRC16_Checkout(data,number));//CRC校检返回值
num=strlen(crc_reg);
if (num==0)
{
sprintf(crc,"0000");//补齐4位校检值
}
else if (num==1)
{
sprintf(crc,"000%s",crc_reg);
}
else if (num==2)
{
sprintf(crc,"00%s",crc_reg);
}
else if (num==3)
{
sprintf(crc,"0%s",crc_reg);
}
else if (num==4)
{
sprintf(crc,"%s",crc_reg);
}
else
{
u2_printf("CRC校检异常");
}
memset(end,0,sizeof(end));//清空
sprintf(end,"%s%s%s%s%s",Head,str,data,CRC_Client,crc);//最终协议组合
WiFi_printf("%s\r\n",end);//发送
OLED_Clear();
OLED_ShowString(0,2,(u8*)"The temp-sensor is working");
delay_ms(10000);
}
else
{
u2_printf("需要连接服务器\r\n");
TIM_Cmd(TIM4,DISABLE);//关闭TIM4
WiFi_RxCounter=0;//清零
memset(WiFi_RX_BUF,0,WiFi_RXBUFF_SIZE);
if(WiFi_Connect_IoTServer()==0)
{
u2_printf("\r\n建立TCP连接成功\r\n");
Connect_flag = 1;
}
}
}
}
// 温度传感器模块
#include "tmp275.h"
void TMP275_Init(void)
{
IIC_Init();
}
void TMP275_Write_Registers(u8 pointer,u8 data)
{
IIC_Start();//发送开始信号,开启传输
IIC_Send_Byte(0x90);//发送器件地址
IIC_Wait_Ack();//等待响应
IIC_Send_Byte(pointer);//设置指向寄存器,指向将要操作的寄存器
IIC_Wait_Ack();
IIC_Send_Byte(data);//发送数据到寄存器
IIC_Wait_Ack();
IIC_Stop();//发送停止信号
}
u16 TMP275_Read_Registers(u8 pointer)
{
u16 temp;
IIC_Start();//发送开始信号,开启读取
IIC_Send_Byte(0x90);//发送器件地址
IIC_Wait_Ack();//等待响应
IIC_Send_Byte(pointer);//设置指向寄存器,指向将要操作的寄存器
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(0x91);//发送数据到寄存器
IIC_Wait_Ack();
temp=IIC_Read_Byte(1);
temp<<=8;//temp左移八位
temp|=IIC_Read_Byte(1);
return temp;
}
float TMP275_Get_Temp(void)
{
short temp1;
float temperature;
temp1=(short)TMP275_Read_Registers(0x00);
temperature=(float)(temp1*0.0625);
return temperature/16;
}
// 温度传感器模块
#ifndef _TMP275_H_
#define _TMP275_H_
#include "stm32f10x.h"
#include "myiic.h"
#include "sys.h"
void TMP275_Init(void);
void TMP275_Write_Registers(u8 pointer,u8 data);
u16 TMP275_Read_Registers(u8 pointer);
float TMP275_Get_Temp(void);
#endif
此处再插一句,在编写温度传感器代码的过程中,因为寄存器问题卡了我好久,不得不说,数据手册上面的寄存器编码真不是常人所能看懂的,所以强烈推荐大家去下载一个寄存器语句生成器,省时省力。
如图
经过了前半段时间的学习和制作,一块初具功能的底层感知系统便搭建完成了。此时便可以进行愉快的调试环节了,这个时候,你会知道bug真的是如鬼影般萦绕你的左右。
硬件调试主要是对电源模块转换电压进行测试以及检测电路中是否有短路、断路(说白了就是测通断)此步操作旨在通电之前查出电路错误,防止单片机被烧坏。
软件调试将通过我们之前预留的串口,直接用调试软件进行调试。此处建议分模块进行测试。先测温度模块,再测WIFI模块,最后再测显示屏模块。
(来个串口代码吧)
#include "stm32f10x.h"
#include "usart2.h"
#if USART2_RX_ENABLE
char Usart2_RxCompleted = 0;
unsigned int Usart2_RxCounter = 0;
char Usart2_RxBuff[USART2_RXBUFF_SIZE];
#endif
void Usart2_Init(unsigned int bound)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
#if USART2_RX_ENABLE
NVIC_InitTypeDef NVIC_InitStructure;
#endif
#if USART2_RX_ENABLE
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
#endif
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = bound;
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;
#if USART2_RX_ENABLE
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
#else
USART_InitStructure.USART_Mode = USART_Mode_Tx ;
#endif
USART_Init(USART2, &USART_InitStructure);
#if USART2_RX_ENABLE
USART_ClearFlag(USART2, USART_FLAG_RXNE);
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
#endif
USART_Cmd(USART2, ENABLE);
}
__align(8) char Usart2_TxBuff[USART2_TXBUFF_SIZE];
void u2_printf(char* fmt,...)
{
unsigned int i,length;
va_list ap;
va_start(ap,fmt);
vsprintf(Usart2_TxBuff,fmt,ap);
va_end(ap);
length=strlen((const char*)Usart2_TxBuff);
while((USART2->SR&0X40)==0);
for(i=0;i<length;i++)
{
USART2->DR = Usart2_TxBuff[i];
while((USART2->SR&0X40)==0);
}
}
#ifndef __USART2_H
#define __USART2_H
#include "stdio.h"
#include "stdarg.h"
#include "string.h"
#define USART2_RX_ENABLE 0 //是否开启接收功能 1:开启 0:关闭
#define USART2_TXBUFF_SIZE 256 //定义串口1 发送缓冲区大小 256字节
#if USART2_RX_ENABLE //如果使能接收功能
#define USART2_RXBUFF_SIZE 256
extern char Usart2_RxCompleted ;
extern unsigned int Usart2_RxCounter;
extern char Usart2_RxBuff[USART2_RXBUFF_SIZE];
#endif
void Usart2_Init(unsigned int);
void u2_printf(char*,...) ;
#endif
调试软件建议大家用win10商店里面的那一个,真心好用。
当你看见以下这个高贵的画面,就说明连接成功了。这个时候数据便源源不断地传到服务器上了。初步调试成功!