基于stm32的智能桌面平台

使用配件:

STM32F103C8T6
DSB8120
DS1302
ESP8266
W25Q64

实现功能:

        OLED屏幕显示多级菜单

        实现联网功能,获取天气,时间

        OLED显示时间,通过联网功能实现更新时间

        监测当前室内温度

        获取天气

ESP8266-01S

        获取天气是使用ESP8266-01S进行联网获取数据。ESP8266-01S使用AT指令进行配置,通过AT指令控制ESP8266_at指令esp8266 可以通过这个文章进行学习,下方我列出此次使用的AT指令。

AT+UART=115200,8,1,0,0 //配置波特率,数据位,停止位,校验位,流控
AT //复位
AT+CWMODE=1 // AP+Station模式
AT+CWJAP="WIFI_Name,"WIFI_Password" //连接wifi
AT+CIPSNTPCFG=1,8 //设置时间地域
AT+CIPSTART="TCP","api.seniverse.com",80 //连接心知服务器
AT+CIPMODE=1 //使能esp8266透传模式
AT+CIPSEND //开启数据传输
GET https://api.seniverse.com/v3/weather/now.json?key=S9eaZ9XPwCwgr8NVc&location=ip&language=zh-Hans&unit=c  //获取天气信息(私钥,城市,语言)

        其中的心知服务器是国内比较知名的天气服务器,首次使用需进入下方网址进行注册,开通免费版即可。网址为:心知天气  

        上方的GET 指令为GET https://api.seniverse.com/v3/weather/now.json?key=S9eaZ9XPwCwgr8NVc&location=ip&language=en&unit=c

        需要进行自己的客制化,key在免费版中可以查看到,location可以输入自己城市的拼音或直接输入ip(使用电脑调试若开了VPN会导致跳到别的城市)而language可以调整回传的数据的格式是中文或英文,详情可见心知天气参考文档心知天气数据目录 HyperData · 心知科技

         首次调试可以使用TTL配置串口调试工具进行调试。接线分别为

TTL                ESP

vcc -------------3.3

gnd -------------gnd

tx    ------------- rx

rx    ------------- tx

        TTL在接线时请注意拔掉跳线帽,确保供电部分连接的是VCC而不是3v3,否则给ESP发送指令时可能会回传busyp...。

         下方是api返回的数据,在EDGE浏览器中出现了大量的空格,而在其他的浏览器中却没有,因此为了节省空间,可以在IRQHandler中忽略空格和冒号。

{
  "results":
    [{
      "location":{
      "id":"WS0E9D8WN298",
      "name":"广州",
      "country":"CN",
      "path":"广州,广州,广东,中国",
      "timezone":"Asia/Shanghai",
      "timezone_offset":"+08:00"},
      "now":{
      "text":"晴",
      "code":"0",
      "temperature":"9"
      },
    "last_update":"2024-03-02T11:52:26+08:00"
    }]
}

       上方是错误的说法,也算是一个坑。真正的json字符串是:

{"results":[{"location":{"id":"WS0E9D8WN298","name":"广州","country":"CN","path":"广州,广州,广东,中国","timezone":"Asia/Shanghai","timezone_offset":"+08:00"},"now":{"text":"中雨","code":"14","temperature":"13"},"last_update":"2024-03-09T23:35:16+08:00"}]}

         

        而api返回的是json格式,但是在回传给单片机的时候已经变成了String格式,所以需要用字符串的方式来进行解析。

        我另外踩到的一个坑是发送AT指令时返回的数据都是比如 OK\r\n 会带有换行符的,而返回的json数据却没有\r\n,所以IRQHandle在检测时不能检测\r\n,需要以时间来检测一帧数据的完成与否。

//IRQ
void USART1_IRQHandler(void)
{
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		RxData[RxDataCnt++] = USART1->DR;	

		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}
char USART1_WaitRecive(void)	//不定长串口接受接口
{
	Recive_Flag = 0;

	if(RxDataCnt == 0){ 							//如果接收计数为0 则说明没有处于接收数据中,所以直接跳出,结束函数
		Recive_Flag = 0;
		return Recive_Flag;
	}	
	if(RxDataCnt == RxDataCntPre)				//如果上一次的值和这次相同,则说明接收完毕
	{
		RxDataCnt = 0;							//清0接收计数
		Recive_Flag = 1;
		return Recive_Flag;								//返回接收完成标志
	}
		
	RxDataCntPre = RxDataCnt;					//置为相同
	
	return Recive_Flag;								//返回接收未完成标志

}

         可以在while里循环调用USART1_WaitRecive进行判断,外加一个延时函数,如延时5ms,意思就是如果延时超过5m数据,则判定为第二帧数据。

        在接收数据后可以使用第三方库cJSON来进行解析,可以在GitHub上进行下载相关文件。

        json相关知识可以查看JSON 基础结构,在返回的json中先包含着数组结构的results,然后包含着对象结构的Location和Now,最后才是最里层的键值对。

void ESP_parse(char *RxData_String){
	cJSON *json,*arrayItem,*object,*subobject,*name,*text,*temperature;
	
	
		json = cJSON_Parse(RxData_String); //解析JSON数据包
	
	if(json == NULL)		  //检测JSON数据包是否存在语法上的错误,返回NULL表示数据包无效
	{
		 //数据包语法错误
		Serial_SendString(USART1,"ERROR");
		
	}
	else
	{
		arrayItem = cJSON_GetObjectItem(json,"results");
		object = cJSON_GetArrayItem(arrayItem,0);
		subobject = cJSON_GetObjectItem(object,"location");
		name = cJSON_GetObjectItem(subobject,"name");
		subobject = cJSON_GetObjectItem(object,"now");
		text = cJSON_GetObjectItem(subobject,"text");
		temperature = cJSON_GetObjectItem(subobject,"temperature");
		
		text_value = text->valuestring,
		temperature_value = temperature->valuestring;
		name_value = name->valuestring;

		Weather(0,0,text_value);
		OLED_ShowString(0,16,temperature_value,OLED_8X16);
		city(0,32,name_value);
		OLED_Update();
	}
	cJSON_Delete(json); //释放cJSON_Parse()分配出来的内存空间
}

        在接收json指令的时候其实是可以接收中文城市和气候的,但是返回的是UTF-8的编码,所以会显示?,如果不打算存入字库的话,也可以把项目改成UTF-8的编码,也不需要再去解析天气和气候了。

        项目在这里卡住了很久,因为在串口调试中显示通过ESP得到的天气数据没有问题,而解析函数也确定没有问题,但是解析出来的结果却是空的,通过查询,发现是内存空间分配较小,使用C8T6的需要Heap_Size,需要改大一些。参考这个关于STM32+cJSON所遇到的一些问题_cjson_parse返回null

    DS1302

        DS1302是一个实时时钟芯片,可以提供秒、分、时、日、月、年等信息,可以决定是12小时制或是24小时制。

        

 秒:读命令地址:0x81,写命令0x80,范围 00-59;

 分:读命令地址:0x83,写命令0x82,范围 00-59;(BIT4-BIT7的值)*10+(BIT0-BIT3的值)=分钟

 时:读命令地址:0x85,写命令0x84,范围 1-12/0-23;

 日:读命令地址:0x87,写命令0x80,范围 1-31;

 月:读命令地址:0x89,写命令0x88,范围 1-12;

 周:读命令地址:0x8B,写命令0x8A,范围 1-7;

 年:读命令地址:0x8D,写命令0x8H,范围 00-99;

void ds1302_init()
{
	ds1302_wirte_rig(0x8e,0x00);//关闭写保护
	ds1302_wirte_rig(0x80,0x55);//seconds37秒
	ds1302_wirte_rig(0x82,0x59);//minutes58分
	ds1302_wirte_rig(0x84,0x23);//hours23时
	ds1302_wirte_rig(0x86,0x30);//date30日
	ds1302_wirte_rig(0x88,0x09);//months9月
	ds1302_wirte_rig(0x8a,0x07);//days星期日
	ds1302_wirte_rig(0x8c,0x24);//year2024年
	
	//ds1302_wirte_rig(0x80,0x19);
	
	ds1302_wirte_rig(0x8e,0x80);//关闭写保护
	
}
void ds1302_read_time(void)
{
	read_time[0]=ds1302_read_rig(0x81);//读秒
	read_time[1]=ds1302_read_rig(0x83);//读分
	read_time[2]=ds1302_read_rig(0x85);//读时
	read_time[3]=ds1302_read_rig(0x87);//读日
	read_time[4]=ds1302_read_rig(0x89);//读月
	read_time[5]=ds1302_read_rig(0x8B);//读星期
	read_time[6]=ds1302_read_rig(0x8D);//读年
}

DS1302中的数据都是以BCD码存储的,因此读出来或写入的数据都应该是BCD码。所以需要转换成十进制。

ds1302_read_time();  //BCD码转换为10进制
	TimeData.second=(read_time[0]>>4)*10+(read_time[0]&0x0f);
	TimeData.minute=((read_time[1]>>4)&(0x07))*10+(read_time[1]&0x0f);
	TimeData.hour=(read_time[2]>>4)*10+(read_time[2]&0x0f);
	TimeData.day=(read_time[3]>>4)*10+(read_time[3]&0x0f);
	TimeData.month=(read_time[4]>>4)*10+(read_time[4]&0x0f);
	TimeData.week=read_time[5];
	TimeData.year=(read_time[6]>>4)*10+(read_time[6]&0x0f)+2000;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值