Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
柿饼_PersimmonUI
【PersimmonUI柿饼学习营】+ A Byte of China + 网络/串口/天气预报
发布于 2018-10-07 20:06:55 浏览:2378
订阅该版
最后一周作业:基于网络和串口的天气预报 实现以下板块: 1,日历板块:要求从网上获取当天各类实时信息,如天气,黄历信息等,显示并记录下来。 2,分析板块:根据日历板块记录的数据信息,使用画布制作出数据分析图(如柱状图等)。 3,能通过串口输入指定日期(一天,或者连续几天),并从串口返回出相应的数据。 **_开发环境_** RTT + PerimmonUI + 野火RT1052Mini + 5寸800*480触屏 ![TIM截图20181007194820.png](/uploads/201810/07/195258hjy5ghghm0ss1a0e.png) **_开发过程_** 本次作业的关键是网络和串口,本次终于可以从UI接触到硬件交互,作业可以分成3部分:**1、网络;2、数据展示;3串口**。1、网络的重点在于使用网络API接口获取需要的数据,通过GET方法我们获取到JSON格式的天气预报,然后对格式进行处理,获得我们需要的对应数据(高低温,天气,风速等) 2、数据展示使用画布来实现,灵感来自折线图,两条折现展示近三天的高低温,三天中的天气通过背景色来区别(晴天为蓝色,多云为灰色,其他为绿色),同时利用定时器回调函数,可以实现折线上升的动画效果;关于城市选择我们通过card控件+城市图片来实现,通过card值来切换城市,进而改变天气预报API地址以获取对应城市的天气,当然获取到的当天天气会通过label展示在预报区之上,整体布局如下。 ![TIM截图20181007194621.png](/uploads/201810/07/195256xk878xaawz5xuba5.png) 3、串口需要解决的问题是对接收到的报文进行组帧在分组,串口询问天气的固定格式为“yyyy-mm-dd n” (yyyy-mm-dd为起始日期,n为1~3,表示需要的天数,因天气预报API限制,只能获取当前三天的数据,如起始日期为明天,需要三天,我们只能获得两天的数据)。获得固定格式的串口数据请求,再将相应的数据返回到串口,如果数据格式有误,会提示正确格式模板。 具体请详见JS源码 app.js源码,主要实现uart串口应用```var strcon_flg = 0; var str1 var str2 var app = { page : "page1/page1", onLaunch: function (event) //app加载回调函数 { console.log('app onLaunch'); uart = pm.openSerialPort({device: "uart5"}); //打开串口设备uart5 if (uart) { console.log('pm.openSerialPort OK'); uart.write(Buffer("Please input the date: e.g '2018-10-01 3' which means 3 days data from 2018-10-01 ", 'ascii')); //串口发送数据,一个ascii字符串数据BUFF uart.onData(this.onUart, this); //设置串口接收函数为 onUart } }, onUart : function (data) //串口接收数据回调函数,data 为串口数据 { if(strcon_flg == 0) { strcon_flg = 1; str1 = data.toString('ascii') return; } else { str2 = data.toString('ascii'); strcon_flg = 0; } var str3 = str1.concat(str2) console.log(str3) str3 = str3.substring(str3.indexOf("2")) console.log(str3) var udate = str3.split(" ") console.log(udate) var x = udate[1] for(var i = 0; i < 3; i++) { console.log(udate[0],' vs ',date*) console.log(x) if(udate[0] == date*) break } if((i >= 3)||(parseInt(x) > 3)) { var str_err = "Invalid date(recent 3 days) or format(2018-10-01 3) " console.log(str_err) uart.write(Buffer(str_err, 'ascii')); } else { var n = parseInt(x); if(i+n > 3) { n = 3; } else { n = i+n } for(var j = i; j < n; j++) { var strj = date[j]+ ' High Temperature: '+ high1[j] + ' Low Temperature:' + low1[j] + '
'; console.log(strj) uart.write(Buffer(strj, 'ascii')); } } } }; App(app);``` page1.js源码,主要实现网络和显示 ```var date = ['2018-09-29','2018-09-30','2018-10-01'] var CITIES = ['beijing','shanghai','guangzhou','nanjing','new'] var City_name = 'Beijing' var code = ['Sunny','Cloudy','Snowy'] var CODE = ['Sunny','Cloudy','Snowy'] var DIRECTION = ['N','E','W','S','NE','NW','SE','SW'] var wind_s = ['20','10','30'] var wind_l = ['2','1','3'] var wind_d = ['W','E','N'] var high = [0, 0, 0] var low = [0, 0, 0] var high1 = [25, 26, 24] var low1 = [15, 10, 17] var DISTANCE = 110 var jsons = '{"results":[{"location":{"id":"WX4FBXXFKE4F","name":"Beijing","country":"CN","path":"Beijing,Beijing,China","timezone":"Asia/Shanghai","timezone_offset":"+08:00"},"daily":[{"date":"2018-09-30","text_day":"Cloudy","code_day":"4","text_night":"Cloudy","code_night":"4","high":"19","low":"13","precip":"","wind_direction":"NW","wind_direction_degree":"315","wind_speed":"20","wind_scale":"4"},{"date":"2018-10-01","text_day":"Sunny","code_day":"0","text_night":"Sunny","code_night":"1","high":"24","low":"12","precip":"","wind_direction":"N","wind_direction_degree":"0","wind_speed":"20","wind_scale":"4"},{"date":"2018-10-02","text_day":"Sunny","code_day":"0","text_night":"Sunny","code_night":"1","high":"24","low":"11","precip":"","wind_direction":"N","wind_direction_degree":"0","wind_speed":"10","wind_scale":"2"}],"last_update":"2018-09-30T11:00:00+08:00"}]}' var json_obj = JSON.parse(jsons) var s1 = 'http://api.seniverse.com/v3/weather/daily.json?key=hfvxxp7oq0w4dmso&location=' var city = 'beijing' var s2 = '&language=en&unit=c&start=' var day = '0' var s3 = '&days=3' var url_w = s1+city+s2+day+s3 var ctx_1 = ' Temp:' var ctx_2 = '~' var ctx_3 = ' Wind Speed:' var ctx_4 = ' Wind Direction:' var ctx_5 = ' Wind Scale: ' var ctx_0 = ' Date:' var i = 0; var j = 0; var dly = 195; var ani_flg = 0; var page = { dataa : {timer1 : 0}, onLoad : function() { var thiz = this; // Register a timer callback function this.dataa.timer1 = setInterval(function() { if((ani_flg & 0x0F) == 0) { for(var k = 0; k < high.length; k++) { if(high[k] < high1[k]){ high[k] += Math.round(high1[k]/5) } else { ani_flg |= 0x10; } if(low[k] < low1[k]){ low[k] += Math.round(low1[k]/5) } else { ani_flg |= 0x20; } } thiz.display(); if((ani_flg & 0xF0) == 0x30) { ani_flg = 0xFF; } } if(dly >= 200) { //thiz.onUpdate() thiz.getSkyInfo() dly = 0; } dly++ }, 50); this.getSkyInfo(); this.display() //this.onUpdate() }, getRndW : function() { for(var k = 0; k < high.length; k++) { high[k] = 0; low[k] = 0; high1[k] = Math.floor(Math.random()*5+20) low1[k] = Math.floor(Math.random()*5+10) code[k] = CODE[Math.floor(Math.random()*3)] wind_s[k] = Math.floor(Math.random()*20) wind_l[k] = Math.floor(Math.random()*10) wind_d[k] = DIRECTION[Math.floor(Math.random()*8)] var ctx = 'Zootopia'+' '+code[0]+ctx_1+low1[0]+ctx_2+high1[0]+ctx_0+date[0] var ctxw = ctx_3+wind_s[0]+ctx_4+wind_d[0]+ctx_5+wind_l[0] this.setData({label1: { value : ctx , refresh : true}}); this.setData({label2: { value : ctxw, refresh : true}}); ani_flg = 0; } }, display : function() { var context = pm.createCanvasContext('Canvas1', this) //获取画布对象 if (context) { var max = 36; for(var j = 0; j < 3; j++) { grd = context.createLinearGradient(0, 0, 0, 480) grd.addColorStop(0, 'black') if(code[j] == 'Sunny') { grd.addColorStop(1, '#FF9090FF') }else if(code[j] == 'Cloudy') { grd.addColorStop(1, 'GRAY') }else { grd.addColorStop(1, '#FFB9FFB9') } // Fill with gradient context.setFillStyle(grd) context.fillRect(60 + j * DISTANCE, 30, DISTANCE , 350) } max = Math.floor(max / 6); /* 画浅灰色竖线竖线 */ context.beginPath(); //开启新路径 context.setStrokeStyle('#C0C0C0') //设置边框颜色 for( index = 1; index <= 3; index++ ) { var y = 380; context.moveTo(60 + index * DISTANCE, y) //线条起点 context.lineTo(60 + index * DISTANCE, 30) //线条终点 } context.stroke() //画线 context.closePath(); //关闭当前路径 /* 画横纵坐标刻度 */ context.beginPath(); //开启新路径 context.setStrokeStyle('black') //设置边框颜色 context.fillText('Temperature', 5, 5) //绘制文字,坐标(5,5) context.setTextBaseline('middle') //设置文本绘制纵坐标对齐方式 for( index = 0; index < 7; index++ ) { var y = 30 + index * 50; var value = max * (7 - index); /*纵坐标刻度*/ context.moveTo(55, y) context.lineTo(60, y) context.fillText(value.toString(), 20, y) } context.moveTo(55, 30 + index * 50) context.lineTo(60, 30 + index * 50) context.fillText('0', 20, 30 + index * 50) context.moveTo(60, 30) context.lineTo(60, 30 + index * 50) context.moveTo(60, 30 + index * 50) context.lineTo(60 + 3 * DISTANCE, 30 + index * 50) context.setTextAlign('center') //设置文本绘制横坐标对齐方式 for( index = 1; index <= 3; index++ ) { var x = 60 + (index-0.5) * DISTANCE; /*横坐标刻度*/ context.moveTo(x, 380) context.lineTo(x, 385) context.fillText(date[index-1], x, 395) } context.setTextAlign('left') //设置文本绘制横坐标对齐方式 context.fillText('Date', 60 + (low.length) * DISTANCE + 10 , 395) context.stroke() context.closePath(); /* High temp */ var x = 60 + DISTANCE/2; context.moveTo(x, 380) context.beginPath(); context.setLineCap('round') context.setStrokeStyle('#FFFF6969') context.setLineWidth(4) //设置线条宽度 for( index = 0; index < high.length; index++ ) { var x = 60 + DISTANCE/2 + index * DISTANCE; var y = high[index] * 350 / (max * 7) context.lineTo(x, 380 - y) context.arc(x, 380 - y, 3, 0, 2 * Math.PI) } context.stroke() context.closePath(); /* Low temp */ var x = 60 + DISTANCE; context.moveTo(x, 380) context.beginPath(); context.setStrokeStyle('#FF6969FF') for( index = 0; index < low.length; index++ ) { var x = 60 + DISTANCE/2 + index * DISTANCE; var y = low[index] * 350 / (max * 7) context.lineTo(x, 380 - y) context.arc(x, 380 - y, 3, 0, 2 * Math.PI) } context.stroke() context.closePath(); // Value context.setTextAlign('center') context.setFillStyle('white') for( index = 0; index < 3; index++ ) { var x = 60 + DISTANCE/2 + index * DISTANCE; var y = high[index] * 350 / (max * 7) context.fillText(high[index].toString(), x, 365-y) var x = 60 + DISTANCE/2 + index * DISTANCE; var y = low[index] * 350 / (max * 7) context.fillText(low[index].toString(), x, 395-y) var x = 60 + DISTANCE/2 + index * DISTANCE; context.fillText(code[index], x, 50) } context.draw(); } }, onUpdate : function(){ //根据json_obj中的数据,来设定对应Label的值 for(var i = 0; i < 3; i++){ high* = 0; low* = 0; City_name = json_obj.results[0].location.name date* = json_obj.results[0].daily*.date code* = json_obj.results[0].daily*.text_day high1* = json_obj.results[0].daily*.high low1* = json_obj.results[0].daily*.low wind_d* = json_obj.results[0].daily*.wind_direction wind_s* = json_obj.results[0].daily*.wind_speed wind_l* = json_obj.results[0].daily*.wind_scale var ctx = City_name+' '+code[0]+ctx_1+low1[0]+ctx_2+high1[0]+ctx_0+date[0] var ctxw = ctx_3+wind_s[0]+ctx_4+wind_d[0]+ctx_5+wind_l[0] this.setData({label1: { value : ctx , refresh : true}}); this.setData({label2: { value : ctxw, refresh : true}}); ani_flg = 0; } }, getSkyInfo: function(e) { var thiz = this; var str =0; url_w = s1+city+s2+day+s3 console.log(url_w) var rq1 = pm.request({ url: url_w, // 获取天气预报的API method : 'GET', header:{ "Content-Type":"application/json" }, success: function(res) { //与开发者服务器连接成功后,执行的回调函数 str = res.data.toString('utf8'); // 把data从Buffer转成string json_obj=JSON.parse(str); //把JSON格式的string转成JSON对象,以便获取数据 thiz.onUpdate(); //更新各个控件的值 }, fail: function(){ console.log('request failed') } }); }, onChange : function(e){ console.log(e.detail.value) console.log(CITIES[e.detail.value]) dly = 0; if(CITIES[e.detail.value] == 'new') { this.getRndW() } else { city = CITIES[e.detail.value] //this.onUpdate() this.getSkyInfo() } } }; Page(page); ``` **_效果展示_** 仿真的界面效果 ![wf.gif](/uploads/201810/07/195301b3mornmr3bbr7o3z.gif) 板子上跑的效果 ![l5-v.gif](/uploads/201810/07/195256lm3ag1k1c33a2p2g.gif) 串口效果 ![l5-2.gif](/uploads/201810/07/195247u28gp219c7o303mp.gif) **_总结_** 本周作业有了硬件的内容,更加嵌入式了,具体功能细节还有待研究。 网络功能很方便,使用内置的http的get方法可以很轻松获取网络资源,小伙伴们可以结合《网络编程学习营》的内容进一步探索更有趣更实用的功能。 串口的使用也很简单,还考虑到串口数据与各个page的交互,这个很不错。 我的js编程还不是很熟,还是用面向过程的方式编写代码,相信开发js的同学来使用柿饼的话应该能写出更高效优美的代码。 这是最后一课,用一句话总结:柿饼通过所见即所得的开发方式和便捷易学的JS脚本语言编程模式颠覆了UI的开发! 整过学习过程的代码我都有放到个人的github中,欢迎一起交流 [https://github.com/ianhom/JavaScript-Noob/tree/master/app/PersimmonUI](https://github.com/ianhom/JavaScript-Noob/tree/master/app/PersimmonUI) 。 熟练使用好柿饼,还有其他效果哦,下图是我使用柿饼快速制作的冒泡排序动图,是不是很方便呢。 后面柿饼正式发布后,期待更多的小伙伴们优秀作品! 感谢柿饼,感谢RT-Thread!! RT-Thread总会给我们相聚的机会,让我们下次再见吧~ ![bubblesort.gif](/uploads/201810/07/195247qehm0xz9qj9jmjne.gif) 柿饼工程 ![hw5-3-4.rar](/uploads/201810/07/200455x0ekechyybfq2e7l.rar)
查看更多
2
个回答
默认排序
按发布时间排序
bernard
2018-10-07
这家伙很懒,什么也没写!
ABC大佬厉害!而且这次又是第一个交作业!
flyboy
2018-10-10
Do my self();
顶一下,看着很流畅,而且这个排序很精髓:loveliness:
撰写答案
登录
注册新账号
关注者
0
被浏览
2.4k
关于作者
ianhom
这家伙很懒,什么也没写!
提问
17
回答
16
被采纳
0
关注TA
发私信
相关问题
1
【PersimmonUI柿饼学习营】+ A Byte of China + 环境搭建&20W年薪广告
2
【柿饼学习营】+werrysuzhen+20W年薪作业
3
【PersimmonUI柿饼学习营】+ meetwit + 20W年薪广告&lesson01
4
【PersimmonUI柿饼学习营】+ DaZhou + 20W年薪作业+视频有彩蛋
5
【PersimmonUI柿饼学习营】+ DMY+ lesson01 20W年薪广告
6
【PersimmonUI柿饼学习营】+ Bigmagic+20W年薪广告&day01
7
【PersimmonUI柿饼学习营】+ chowguohua+年薪广告
8
【柿饼学习营】+werrysuzhen+脚本及事件学习
9
【PersimmonUI柿饼学习营】+ DaZhou+ 手把手教你做计算器
10
【PersimmonUI柿饼学习营】+ A Byte of China + 2048游戏
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
在用clangd开发RTT吗,快来试试如何简单获得清晰干净的工作区
2
GD32F450 片内 flash驱动适配
3
STM32H7R7运行CherryUSB
4
RT-Smart首次线下培训,锁定2024 RT-Thread开发者大会!
5
使用RC522软件包驱动FM1722
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
freemodbus
PWM
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
中断
编译报错
Debug
SFUD
rt_mq_消息队列_msg_queue
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
a1012112796
10
个答案
1
次被采纳
踩姑娘的小蘑菇
4
个答案
1
次被采纳
红枫
4
个答案
1
次被采纳
张世争
4
个答案
1
次被采纳
Ryan_CW
4
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
6
次点赞
YZRD
2
篇文章
5
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
Woshizhapuren
1
篇文章
5
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部