今天是个好日子,Linux嵌入式专题终于开篇了,记录于2011.12.14
在固件开发中,常会用到串口。在各种芯片spec中,串口称作UART,而在PC上总叫做RS232。由于历史原因,IBM的PC外部接口配置为RS232,成为实际上的PC界默认标准。
COM口是指针对串行通信协议的一种端口,是PC上异步串行通信口的简写,大部分为9针孔D型。COM口里分RS232,RS422和RS485,传输功能依次递增。
TTL全名是晶体管-晶体管逻辑集成电路(Transistor-Transistor Logic),这种串行通信,对应的物理电平,始终是在0V和Vcc之间,其中常见的Vcc是5V或3.3V。
关系:
UART更多关注规定编码格式的标准,如波特率(baud rate)、帧格式和波特率误差等等。RS232和TTL更多是电平标准和电压,他们在软件协议层面是一样的,如对于同样传输0b01010101来说。
I²C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息,因此I2C总线简化了硬件电路PCB布线,降低了系统成本,提高了系统可靠性。 Arduino上也称为 TWI。
I²C被应用在简单且其制造成本 > 传输速度更为重要的外设上。
传感器和执行器是常见的I²C使用案例,例如包含加速度计,温度计,LCD显示器,和电机驱动。
SPI是串行外设接口(Serial Peripheral Interface)的缩写,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,速率最高可达50MHz,许多传感器除了I²C也支持SPI。
SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时)。它们是MISO(主设备数据输入)、MOSI(主设备数据输出)、SCLK(时钟)、CS(片选)。
模拟数字转换器即A/D转换器,或简称ADC,通常是指一个将模拟信号转变为数字信号的电子元件。A/D转换一般要经过取样、保持、量化及编码4个过程。
模拟信号是指用连续变化的物理量所表达的信息,如温度、湿度、压力、长度、电流、水流,电压等等,我们通常又把模拟信号称为连续信号,它在一定的时间范围内可以有无限多个不同的取值。而数字信号是指在取值上是离散的、不连续的信号。
RTC是实时时钟的缩写(Real_Time Clock),通常称为时钟芯片,它为人们提供精确的实时时间,或者为电子系统提供精确的时间基准,目前实时时钟芯片大多采用精度较高的晶体振荡器作为时钟源。
RTC的晶振频率为什么是32768Hz?
石英钟内部分频器只能进行15次分频,要是换成别的频率的晶振,15次分频后就不是1Hz的秒信号,钟就不准了; 经过工程师的经验总结32768 Hz,时钟最准确; 规范和统一;
晶振一般叫做晶体谐振器,是一种能把电能和机械能相互转化的晶体在共振的状态下工作,以提供稳定,精确的单频振荡,是用电损耗很小的石英晶体经精密切割磨削并镀上电极焊上引线做成。
晶振的作用是为系统提供基本的时钟信号。通常一个系统共用一个晶振,便于各部分保持同步。有些通讯系统的基频和射频使用不同的晶振,而通过电子调整频率的方法保持同步。晶振通常与锁相环电路配合使用,以提供系统所需的时钟频率。如果不同子系统需要不同频率的时钟信号,可以用与同一个晶振相连的不同锁相环来提供。
锁相环是一种反馈电路,用来统一整合时钟信号,其作用是使得电路上的时钟和某一外部时钟的相位同步。
许多电子设备要正常工作,通常需要外部的输入信号与内部的振荡信号同步。
一般的晶振由于工艺与成本原因,做不到很高的频率,而在需要高频应用时,由相应的器件VCO,实现转成高频,但并不稳定,故利用锁相环路就可以实现稳定且高频的时钟信号。
user: pi pass: raspberry
iwconfig | grep wlan # 判断无线网卡有没有驱动 sudo iwlist wlan0 scan | grep SSID # 扫描 ssid # SSID=shaohy password=xxxx wpa_passphrase SSID password >> /etc/wpa_supplicant/wpa_supplicant.conf sudo chmod 600 /etc/wpa_supplicant/wpa_supplicant.conf #reboot wpa_cli status #查看连接状态
/etc/dhcpcd.conf
interface wlan0 static ip_address=192.168.11.8 static routers=192.168.11.1 static domain_name_servers=202.101.172.35 202.96.96.68
sudo dpkg-reconfigure tzdata
可以在SD卡的根目录下新建一个ssh的空白文件(无后缀),系统启动时发现此文件会自动打开ssh
pi@raspberrypi:~ $ cat /proc/version Linux version 4.9.41+ (dc4@dc4-XPS13-9333) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611) ) #1023 Tue Aug 8 15:47:12 BST 2017 pi@raspberrypi:~ $ cat /etc/os-release PRETTY_NAME="Raspbian GNU/Linux 9 (stretch)" NAME="Raspbian GNU/Linux" VERSION_ID="9" VERSION="9 (stretch)" ID=raspbian ID_LIKE=debian HOME_URL="http://www.raspbian.org/" SUPPORT_URL="http://www.raspbian.org/RaspbianForums" BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"
# sudo vi /etc/apt/sources.list deb http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ stretch main non-free contrib deb-src http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ stretch main non-free contrib # sudo apt-get update
增加对exFAT的支持
sudo apt-get install fuse-exfat sudo apt-get install exfat-utils sudo mount -t exfat /dev/sdb1 /media/exfat
Micro:Bit(也叫做BBC Micro Bit)是基于ARM架构的嵌入式系统,是由英国广播电视公司(BBC)为青少年编程教育设计,联合微软,三星,ARM,英国兰卡斯特大学等共同完成开发的一款微型电脑用途主要针对中小学生编程教育。
电路板大小为4cm×5cm,拥有1个ARM Cortex-M0处理器,加速度传感器和磁力传感器,蓝牙通信和USB连接编程能力,由25个LED组成的显示屏,2个可编程按钮,可以用USB或者外部电池包来供电[2]。设备输入和输出包括环孔连接器和边缘连接器。
服务器查看网卡配置
d -- 禁用 p -- 物理活动唤醒 u -- 单播消息唤醒 m -- 多播(组播)消息唤醒 b -- 广播消息唤醒 a -- ARP 唤醒 g -- 特定数据包magic packet唤醒 s -- 设有密码的特定数据包magic packet唤醒 /etc/udev/rules.d/81-wol.rules ACTION=="add", SUBSYSTEM=="net", NAME=="en*", RUN+="/usr/bin/ethtool -s $name wol g"
现在我们还可让OpenWRT路由器每天定时唤醒NAS
0 9 * * * /usr/bin/etherwake -i br-lan -b A8:A1:59:67:DE:22
OpenWrt 是嵌入式设备上的 Linux 发行版,主要用于家庭路由器。
PandoraBox 基于OpenWrt,是OpenWrt变种的一个分支,功能更丰富。
LEDE 同样是 OpenWrt 的一个开源分支,LEDE 的全称是 “Linux Embedded Development Environment”,它的目标是让嵌入式设备上的 Linux 发行版变得更加易用。
我这里用的是小米路由器3C,其他型号的路由器自行选择下载相应的系统。
src/gz openwrt_dist http://openwrt-dist.sourceforge.net/releases/ramips/packages src/gz openwrt_dist_luci http://openwrt-dist.sourceforge.net/releases/luci/packages
装了1.6的luci就可以了
如果是青春版,需要手工设置开机启动:
/etc/init.d/dropbear start nvram set ssh_en=1; nvram commit
/etc/rc.local
# restore phy config export TERM='xterm-256color' export TERM='linux' speed=$(uci -q get xiaoqiang.common.WAN_SPEED) [ -n "$speed" ] && /usr/sbin/phyhelper swan "$speed" /etc/init.d/stunserver stop /etc/init.d/filetunnel stop mount -o bind /userdisk/opt /opt export PATH=/opt/sbin:/opt/bin:$PATH #opkg update ## Config firewall cat > /etc/firewall.user <<EOF /sbin/sysctl -w net.ipv4.ip_forward=1 /sbin/sysctl -w net.ipv4.tcp_fastopen=3 ipset -N gfwlist iphash iptables -t nat -A PREROUTING -p tcp -m set --match-set gfwlist dst -j REDIRECT --to-port 1081 iptables -t nat -A OUTPUT -p tcp -m set --match-set gfwlist dst -j REDIRECT --to-port 1081 EOF ## Config shadowsocks init script ##curl https://raw.githubusercontent.com/blademainer/miwifi-ss/master/mini/shadowsocks_mini.tar.gz if [ -s /extdisks/sda1/shadowsocks.json ];then rm -rf /tmp/etc/dnsmasq.d/gfwlist.conf ln -snf /extdisks/sda1/shadowsocks.json /etc/shadowsocks.json fi mkdir -p /userdisk/sysapihttpd/shadowsocks/bin chmod +x /extdisks/sda1/shadowsocks_mini/ss-redir ln -snf /extdisks/sda1/shadowsocks_mini/ss-redir /userdisk/sysapihttpd/shadowsocks/bin chmod +x /extdisks/sda1/shadowsocks_mini/shadowsocks ln -snf /extdisks/sda1/shadowsocks_mini/shadowsocks /etc/init.d/shadowsocks /etc/init.d/shadowsocks start ## Config dnsmasq [ -x /root/check_gfwlist.sh ] && /root/check_gfwlist.sh sleep 5 /etc/init.d/firewall restart
check_gfwlist.sh
#!/bin/ash dir="/extdisks/sda1/" cd $dir curl -X GET -u "shaohy:geminis****" http://xxxx.upyun.com/resource/gfwlist.conf -o $dir/temp_gfwlist while read line;do sed -r -i "/$line/d" $dir/temp_gfwlist echo -en "server=/$line/115.231.xx.xx#5533\nipset=/$line/gfwlist\n" >> $dir/temp_gfwlist done < $dir/domain.list ### black-list sed -r -i '/Last Updated/d' $dir/temp_gfwlist sed -r -i '/tt666yy/d' $dir/temp_gfwlist cmp $dir/temp_gfwlist $dir/gfwlist.conf if [ $? = 1 ];then echo Yes mv $dir/gfwlist.conf $dir/gfwlist.conf.bak mv $dir/temp_gfwlist $dir/gfwlist.conf ln -snf $dir/gfwlist.conf /etc/dnsmasq.d/gfwlist.conf /usr/sbin/ipset flush gfwlist /etc/init.d/dnsmasq restart /etc/init.d/firewall restart fi
domain.list
youtube.com inoreader.com brython.info google.com google.com.hk google.hk github.com poe.com truenas.com pypi.org pop-os.com unpkg.com quarto.org python.org server-world.info
add_domain.sh
#!/bin/ash dir="/extdisks/sda1/" cd $dir ### black-list for line in tt666yy.com;do sed -r -i "/$line/d" $dir/gfwlist.conf echo -en "server=/$line/115.231.xx.xx#5533\nipset=/$line/gfwlist\n" >> $dir/gfwlist.conf done /etc/init.d/dnsmasq restart /etc/init.d/firewall restart
加个定时做程序存活检查
crontab -e */20 * * * * ps | grep ss-redir |grep -v grep; [ $? = 1 ] && /etc/init.d/shadowsocks start >/dev/null 2>&1 */15 * * * * /extdisks/sda1/check_wanip.sh 0 5 * * 5 /extdisks/sda1/check_gfwlist.sh 0 4 30 * * /sbin/reboot 0 0 * * * gfwlist2dnsmasq.sh -d 115.231.xx.xx -p 5533 -s gfwlist -o /gfwlist.conf
防火墙保护coredns
iptables -I INPUT ! -s 115.200.254.224 -p udp --dport 5533 -j DROP
/sbin/sysctl -w net.ipv4.ip_forward=1
国内主机 ← iptables nat → 国外主机
-I PREROUTING -i eth0 -p udp --dport 5533 -j DNAT --to-destination 129.227.xx.xx:5533 -I POSTROUTING -d 129.227.xx.xx -p udp --dport 5533 -j SNAT --to-source 115.231.xx.xx
国外主机 ← iptables nat → 国外公网dns
-I PREROUTING -p udp --dport 5533 -j DNAT --to-destination 1.1.1.1:53 -I POSTROUTING -p udp -d 1.1.1.1 --dport 53 -j SNAT --to-source 129.227.xx.xx
DNSMASQ 是一个轻量级的DNS和DHCP 服务器,大约 200 多 KB,并且完整的包含了 DNS 服务器和 DHCP 服务器功能,非常适合 flash 空间有限的嵌入式系统。DNSMASQ作为OpenWrt默认的DNS 服务器和转发器,同时还承担了DHCP的角色。
AdGuardHome 是 AdGuard 开源的一个私人 DNS 服务端,只需在网关部署,即可实现全局域网的广告拦截与隐私反追踪。在 DNS 解析的过程中,匹配规则库内的 URL 进行拦截,同时在客户端中,还可以通过自定义过滤规则实现网页 DOM 的拦截。最大的感受就是开屏广告和微信朋友圈广告都没了。而且GITHUB上还有这个gfwlist2adguardhome,也可以转换gfwlist的规则。
之前的小米3C路由器性能偏弱,所以一直都是使用dnsmasq+ipset+ss做的轻量级方案,这次换成红米AC2100【mt7621且只有128M内存,容易OOM】, 不如 磊科N60 pro ,是时候上AdGuardHome+gfwlist大杀器了。
/extdisks/sda2/check_wanip.sh
#!/bin/ash LOG="/root/ip.log" DDNS_v6="https://dynv6.com/api" token="zFcJgsVX_9iB-ELKfSshJSzGzjR2zxs#s#tt666yy#" hostname="shaohy.v6.xxxx" USERPASS="xxx:xyy_xxxx" nslookup www.qq.com|grep -i "Address.*192.168.31.1" [ $? = 0 ] && /sbin/reboot [ -f $LOG ] && IP1=$(cat $LOG) [ -z $IP1 ] && IP1="0.0.0.0" #IP=$(ifconfig |awk '/pppoe-wan/,/inet/{split($2,a,":");if(a[2] ~ /[0-9*]/) {print a[2]}}') #IP6=$(curl -6 ifconfig.me) IP=$(curl -4 ifconfig.me) [ -z $IP ] && IP=$(curl -4 ifconfig.me) echo "old: $IP1 new: $IP" if [ $IP != $IP1 ];then while [ $IP != $IP1 ];do echo "$(date): Updating the DNS." curl -k "https://$DDNS_v6/update?token=${token}&zone=${hostname}&ipv4=${IP}" sleep 15 IP1=$(nslookup $hostname|awk '/Address 1/{print $NF}') done echo $IP >$LOG curl -k -X PUT -u $USERPASS -T $LOG http://xxxx.upyun.com/ip.log fi
httpd.conf
server { listen 88; server_name xxxx.upyun.com; access_log off; auth_basic "input password: "; auth_basic_user_file conf.d/auth.conf; location / { dav_methods PUT; create_full_put_path on; dav_access group:rw all:r; root html/resource; } }
yum install gcc gettext autoconf libtool automake make pcre-devel asciidoc xmlto c-ares-devel libev-devel libsodium-devel mbedtls-devel -y git submodule update --init --recursive sh autogen.sh ./configure --prefix=/opt/ss --disable-documentation make make install
ss-redir.json
{ "server":"114.230.101.91", "server_port":58888, "local_port":1081, "local_address": "0.0.0.0", "password":"Gxxxxcc$iqdPdfaadfsdxxxtytyn", "timeout":600, "method":"aes-256-cfb", "mode": "tcp_and_udp" }
/etc/systemd/system/ss-redir.service
[Unit] Description=ss-redir After=network-online.target [Service] Type=simple ExecStart=/opt/bin/ss-redir -c /opt/bin/config.json KillMode=process Restart=on-failure RestartSec=1min [Install] WantedBy=multi-user.target # systemctl daemon-reload # systemctl start ss-redir
#!/bin/sh /etc/rc.common # Copyright (C) 2006-2011 OpenWrt.org START=95 SERVICE_USE_PID=1 SERVICE_WRITE_PID=1 SERVICE_DAEMONIZE=1 CONFIG_FILE=/etc/shadowsocks.json start() { echo 3 > /proc/sys/net/ipv4/tcp_fastopen service_start /userdisk/sysapihttpd/shadowsocks/bin/ss-redir -c $CONFIG_FILE -b 0.0.0.0 } stop() { echo 0 > /proc/sys/net/ipv4/tcp_fastopen service_stop /userdisk/sysapihttpd/shadowsocks/bin/ss-redir } restart() { stop start }
iptables转发规则
iptables -t nat -N HOLDON iptables -t mangle -N HOLDON iptables -t nat -A HOLDON -d 47.240.128.146 -j RETURN iptables -t nat -A HOLDON -d 192.168.22.133 -j RETURN iptables -t nat -A HOLDON -d 0.0.0.0/8 -j RETURN iptables -t nat -A HOLDON -d 10.0.0.0/8 -j RETURN iptables -t nat -A HOLDON -d 127.0.0.0/8 -j RETURN iptables -t nat -A HOLDON -d 169.254.0.0/16 -j RETURN iptables -t nat -A HOLDON -d 172.16.0.0/12 -j RETURN iptables -t nat -A HOLDON -d 192.168.0.0/16 -j RETURN iptables -t nat -A HOLDON -d 224.0.0.0/4 -j RETURN iptables -t nat -A HOLDON -d 240.0.0.0/4 -j RETURN iptables -t nat -A HOLDON -p tcp -j REDIRECT --to-ports 1080 iptables -t nat -A PREROUTING -p tcp -j HOLDON iptables -t mangle -A PREROUTING -j HOLDON
你当然可以直接用Shell客户端安装你要的应用,但后续还有配置等问题,所以建议安装Misstar Tools实现界面化设置,还可以安装其他的插件,比如去广告之类,具体安装完后自己登录路由管理界面去看。
在SSH客户端界面输入以下命令安装:
#!/bin/sh #---------------------------------------------------------------- # Shell Name:install # Description:Plug-in install script # Author:Starry # E-mail: starry@misstar.com # Time:2016-11-06 02:30 CST # Version: 1.6.11.07 # Copyright © 2016 Misstar Tools. All rights reserved. #----------------------------------------------------------------*/ clear ## Check The Router Hardware Model model=$(uname -m) cd /tmp/ curl -s -k https://mirror1.misstar.com/download/$model/mtinstall -o /tmp/mtinstall if [ $? != 0 ];then curl -s -k https://mirror2.misstar.com/download/$model/mtinstall -o /tmp/mtinstall if [ $? != 0 ];then echo "下载程序失败,即将退出" exit fi fi chmod +x /tmp/mtinstall /tmp/mtinstall
或者
wget http://www.misstar.com/tools/appstore/install.sh -O /tmp/install.sh chmod +x /tmp/install.sh && /tmp/install.sh ------安装完成 请牢记以下信息----- 用户名:root 密 码:c92eb800_987 工具箱:http://192.168.31.1:1024 工具箱:http://mt.misstar.com:1024
SSH登录到路由,然后运行以下命令:
/etc/misstar/scripts/appmanager add ss
安装完成后刷新插件界面,应该可以看到一个科学上网了。
mkdir -p /userdisk/opt mount -o bind /userdisk/opt /opt cd /userdisk/opt wget http://pkg.entware.net/binaries/mipsel/installer/installer.sh chmod +x installer.sh ./installer.sh
export PATH=/opt/sbin:/opt/bin:$PATH opkg update opkg install mtr wget ca-certificates openssl-util ca-bundle
开机自动mount和加入环境变量
echo "mount -o bind /userdisk/opt /opt" >> /etc/rc.local echo "export PATH=/opt/sbin:/opt/bin:$PATH" >> /etc/profile
到 openwrt 官网下载中心 找到小米 mini 路由器(R1C)的刷机包,下载;
Linux $ scp openwrt.bin root@192.168.31.1:/tmp xiaomi # cd /tmp xiaomi # mtd -r write openwrt.bin OS1
没有报错,刷机成功。
等路由器重启完成后,连接一个开头为PandoraBox_的无线网络,进入管理平台后,修改root用户的密码,设置网络。
后台地址为:http://192.168.1.1 默认用户名为 root,密码为 admin
官方源的访问速度真的是龟速,甚至有时候由于某种神秘力量导致无法直接使用,我们得替换掉官方源,替换源可以直接编辑源配置文件,也可以在管理页面配置。
嵌入式硬件繁多,不同 CPU 的路由器 OpenWrt 源的配置略有差别,根据自己的型号配置,这里以小米路由器 mini 的 LEDE 为例,CPU 是 MT7620。
源配置文件的路径: /etc/opkg/distfeeds.conf
前往配置 菜单栏 > Software > Configuration > Distribution feeds
#src/gz reboot_core http://downloads.lede-project.org/releases/17.01.1/targets/ramips/mt7620/packages #src/gz reboot_base http://downloads.lede-project.org/releases/17.01.1/packages/mipsel_24kc/base #src/gz reboot_luci http://downloads.lede-project.org/releases/17.01.1/packages/mipsel_24kc/luci #src/gz reboot_packages http://downloads.lede-project.org/releases/17.01.1/packages/mipsel_24kc/packages #src/gz reboot_routing http://downloads.lede-project.org/releases/17.01.1/packages/mipsel_24kc/routing #src/gz reboot_telephony http://downloads.lede-project.org/releases/17.01.1/packages/mipsel_24kc/telephony src/gz reboot_core http://mirrors.ustc.edu.cn/lede/releases/17.01.1/targets/ramips/mt7620/packages src/gz reboot_base http://mirrors.ustc.edu.cn/lede/releases/17.01.1/packages/mipsel_24kc/base src/gz reboot_luci http://mirrors.ustc.edu.cn/lede/releases/17.01.1/packages/mipsel_24kc/luci src/gz reboot_packages http://mirrors.ustc.edu.cn/lede/releases/17.01.1/packages/mipsel_24kc/packages src/gz reboot_routing http://mirrors.ustc.edu.cn/lede/releases/17.01.1/packages/mipsel_24kc/routing src/gz reboot_telephony http://mirrors.ustc.edu.cn/lede/releases/17.01.1/packages/mipsel_24kc/telephony
不难看出,以上配置注释了官方源,使用了 mirrors.ustc.edu.cn 的反代加速。
默认的语言是英文,更换中文需要安装 luci-i18n-base-zh-cn 语言包。安装软件包可以使用包管理工具 opkg,也可以在图形界面 Software 选项找到相关的包来安装。
opkg update
opkg install luci-i18n-base-zh-cn
安装好中文语言包,登录管理后台,前往设置页面更改
System > Language Style > Language,选择 普通话(Chinese)
openwrt换源 清华大学OpenWRT软件仓库
要搞就搞一台真正的NAS服务器 + 小爱wifi插座(定时开关省电)
Contiki is an open source operating system for the Internet of Things. Contiki connects tiny low-cost, low-power microcontrollers to the Internet.
M5Stack产品的核心是Core积木,这个积木内由ESP32担任主控芯片(更早先的募资阶段似是先使用ESP8266)。 Core的底部可以弹性换装不同的Module积木,例如无线通讯模块、电池模组等,Module能够以一个Core为基础进行复数叠放连接;Core也可向外连接不同的Unit积木,Unit即为各种传感器或致动器,如加速度传感器、震动马达等。
char * arrayURL[5] = { "https://lhttp.qingting.fm/live/15318146/64k.mp3", "http://jenny.torontocast.com:8134/stream", "http://188.165.212.154:8478/stream", "http://naxos.cdnstream.com:80/1255_128", "http://149.56.195.94:8015/steam" }; String arrayStation[5] = { "Hangzhou City Info", "Mega Shuffle", "Way Up Radio", "Lite Favorites", "MAXXED Out" };
from m5stack import * from m5ui import * from uiflow import * import urequests def buttonA_wasPressed(): req = urequests.request( method='GET', url='http://xxx.upyun.com/m5api.html', headers={'Content-Type':'text/html'} ) lcd.clear(0x7f1270) label0 = M5TextBox(138, 108, req.text , lcd.FONT_UNICODE, 0xFFFFFF, rotate=0) btnA.wasPressed(buttonA_wasPressed)
from m5stack import * from m5ui import * from uiflow import * from m5mqtt import M5mqtt lcd.clear() x, y = 20, 108 label0 = M5TextBox(x, y, 'Hello, Man !' , lcd.FONT_UNICODE, 0xFFFFFF, rotate=0) m5mqtt = M5mqtt( client_id="m5stick", server="broker-cn.emqx.io", port=1883, user=None, password=None, keepalive=300, ssl=False, ssl_params=None ) def toneCtrl(count): speaker.setVolume(10) for _ in range(count): speaker.tone(500, 50) speaker.tone(1000, 50) def ledCtrl(count): for _ in range(count): M5Led.on() wait_ms(100) M5Led.off() wait_ms(100) def callback(topic_data): toneCtrl(10) lcd.clear() label0 = M5TextBox(x, y+20, topic_data , lcd.FONT_UNICODE, 0xFFFFFF, rotate=0) ledCtrl(3) def butB_wasPressed(): lcd.clear() label0 = M5TextBox(x, y+100, "Good Luck !" , lcd.FONT_UNICODE, 0xFFFFFF, rotate=0) def buttonA_wasPressed(): toneCtrl(5) m5mqtt.publish('shao-corp', "Hi UPYUN!") ledCtrl(1) m5mqtt.subscribe(str('shao-home'), callback) m5mqtt.start() while True: wait_ms(300) btnA.wasPressed(buttonA_wasPressed) btnB.wasPressed(butB_wasPressed)