【玄铁杯第三届RISC-V应用创新大赛】华山派外设接入,I2C与GPIO,蜂鸣器的使用,...
[复制链接]
本帖最后由 eew_dy9f48 于 2023-10-19 15:30 编辑
这周的计划是调通华山派的各种外设使用,并为最终制作老人防跌倒装置做好准备。
我预想的老人防跌倒装置需要包含以下这些功能:
1,跌倒检测:这需要外置运动传感器的使用,项目中使用的是常见的MPU-6050,因此我们需要调通i2c通讯。
2,报警装置:如果检测到跌倒,需要播放警报以引起周围人的注意,因此我们需要使用GPIO,来操纵蜂鸣器工作。
3,邮件求助:检测到跌倒的同时,应同步发送一封求助邮件到预设的邮箱,以尽快获得帮助。要实现这个功能,我们首先需要调通板载的wifi,其次需要使用stmp服务来发送邮件。
看了一下资料,华山派上并不可以运行python。传统C语言较为硬核,虽然资料很丰富,但奈何水平有限。由于官方资料中关于外设的部分都是在shell下控制的,因此这个项目我打算使用一种比较异类的方式完成,将整个程序写在shell中,并通过sh脚本来运行。
首先看一下外置运动传感器的使用。参考下面的原理图:
我们找到I2C引脚的位置,注意这个i2c是i2c3,原理图上有标注,在使用时不要搞错。
将MPU6050的VCC, GND, SDA. SCL四根线接好后,我们试着运行下 i2c-tool命令:
得到以下输出:
- [root@cvitek]/mnt/data
- 0 1 2 3 4 5 6 7 8 9 a b c d e f
- 00: -- -- -- -- -- -- -- -- -- -- -- -- --
- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
- 60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
- 70: -- -- -- -- -- -- -- --
谢天谢地,linux环境中已经自带了i2c-tool,这省去了我们很多麻烦。从输出中我们可以看到,已经可以正确识别到MPU6050,地址是0x68.
那么下一步,我们需要初始化它。网上有很多MPU6050的驱动,因此并不需要去啃规格书。随便找一个C语言的驱动程序,找到初始化部分代码,其实就是一系列寄存器的写入操作。我们只需要把它转换为用i2c-tool写入就可以了。具体初始化代码如下:
- i2cset -y 3 0x68 0x6B 0x80
- sleep 1
- i2cget -y 3 0x68 0x75
- i2cset -y 3 0x68 0x6B 0x00
- sleep 1
- i2cset -y 3 0x68 0x19 0x07
- i2cset -y 3 0x68 0x1A 0x06
- i2cset -y 3 0x68 0x1B 0x18
- i2cset -y 3 0x68 0x1C 0x01
初始化完成后,我们就可以正常读取到MPU6050的数值。所有的数值都是2字节输出,MSB在前,LSB在后,int16结构。因此我们需要先写一个简单的函数来读数,并将它转换成我们可读的数字:
- get_value(){
- let "val=$(i2cget -y 3 0x68 $1)<<8|$(i2cget -y 3 0x68 $(echo "obase=16; $(($1+0x01))" | bc))"
- if [ $val -gt 32767 ];
- then
- val=$(( $val - 65536 ))
- fi
- echo $val
- }
这个函数使用时需要传入一个参数,也就是我们所需要读的数据的MSB地址。我们可以测试一下读取温度,并根据规格书中的公式进行一下转换:
- temp=`get_value 0x41`
- temp=$(echo "scale=2; ($temp/340)+36.53" | bc)
- echo $temp
得到输出25.21,嗯非常正常的一个温度,那么接下来我们再读取一下加速度计和陀螺仪的数字:
- while [ TRUE ]
- do
-
- ax=`get_value 0x3B`
- ay=`get_value 0x3D`
- az=`get_value 0x3F`
- ax=$(echo "scale=2; $ax/16384" | bc)
- ay=$(echo "scale=2; $ay/16384" | bc)
- az=$(echo "scale=2; $az/16384" | bc)
-
- gx=`get_value 0x43`
- gy=`get_value 0x45`
- gz=`get_value 0x47`
- gx=$(echo "scale=2; $gx/16.4" | bc)
- gy=$(echo "scale=2; $gy/16.4" | bc)
- gz=$(echo "scale=2; $gz/16.4" | bc)
-
- echo "ax: $ax"
- echo "ay: $ay"
- echo "az: $az"
-
- echo "gx: $gx"
- echo "gy: $gy"
- echo "gz: $gz"
-
- done
-
然后我们看一下效果:
看起来一切都很正常。至此,MPU6050外设我们已经可以成功使用。
接下来是蜂鸣器的使用。因为主要的目的是发出警报,因此蜂鸣器的音量很关键。在这里我们选用一颗有源蜂鸣器,用NMOS管来驱动,以实现大音量。
参考上面的原理图,在I2C附近有一个GPIOB22,我们就使用这个引脚来控制蜂鸣器吧。
接线一共有三根,mos管的门级接GPIOB22,接着接好供电和地线即可。
蜂鸣器控制比较简单,只需要使用常规GPIO操作方法即可。需要注意的是,linux系统中的GPIO index与实际电路的对应关系如下:
GPIO 编号 = GPIO 组号值 + 偏移值.
以我们选用的管脚为例,查表对应 GPIOB22 GPIOB 对应组号值 448, 偏移值为 22.
因此 GPIOB22 编号index为 448 + 22 = 470
组号值对应如下:
GPIOA 对应 linux 组号值为 480
GPIOB 对应 linux 组号值为 448
GPIOC 对应 linux 组号值为 416
GPIOD 对应 linux 组号值为 404
GPIOPWR 对应 linux 组号值为 381
因此,初始化GPIOB22,并将其设置为输出模式,我们需要用以下命令:
- echo 470 > /sys/class/gpio/export
- echo out > /sys/class/gpio/gpio470/direction
在这里我硬件设计上出了点小问题。
由于华山派的GPIO在未定义状态下是默认上拉的,当我们将它设置为输出模式后,才会变成低电平。而我的蜂鸣器是使用NMOS驱动,高电平有效,这就导致在初始化管脚前蜂鸣器会一直叫,直到初始化完成后才会停止,非常烦人。如果大家想自己做,建议使用PMOS,就不会有这个问题。
接下来我们尝试下让蜂鸣器鸣叫五秒,接着关闭:
- echo 1 > /sys/class/gpio/gpio470/value
- sleep 5
- echo 0 > /sys/class/gpio/gpio470/value
可以听到蜂鸣器正常工作,那么这一块我们也就完成了。
下面我们来说说如何连接WiFi。WiFi连接比较麻烦,主要是官方资料中的内容不是缺失就是错误,导致耽误了很多时间。最后在平头哥工程师的帮助下,终于在硬十上找到了一篇正确的资料,这才成功连接。
首先我们去以下地址下载所需的可执行文件:
https://www.hw100k.com/play?id=195&chapterId=2572
下载完成后,我们在华山派的/mnt/data中新建一个WiFi文件夹,将下载里面的wpa_cli和wpa_supplicant放进去,然后输入以下命令赋予执行权限:
- chmod +x wpa_cli
- chmod +x wpa_supplicant
然后新建一个wpa_supplicant.conf的文件,将以下代码输入进去:
- ctrl_interface=/var/run/wpa_supplicant
- update_config=1
- network={
- ssid="SSID1"
- psk="password1"
- }
- network={
- ssid="SSID2"
- psk="password2"
- }
修改好自己的SSID和password,你有几个可以连接的AP就填几个network,程序会按照顺序一个一个尝试连接,如果连不上超时就换下一个。
完成后我们在/mnt/data中新建一个auto.sh文件,按照上文方法添加执行权限,接着在里面写入以下内容:
- insmod /mnt/system/ko/3rd/8723ds.ko
- ifconfig wlan0 up
- /mnt/data/WiFi/wpa_supplicant -i wlan0 -Dnl80211 -c /mnt/data/WiFi/wpa_supplicant.conf &
- udhcpc -b -i wlan0 -R &
然后重启,我们就可以发现板子已经成功的连上了WiFi,可以不再需要接线,用ssh直接透过wifi连接使用,非常方便。
但这板子有一个比较蛋疼的地方是,每一次重新启动,似乎网卡的信息都会改变。经过测试,每次重启有线网卡的mac地址都不相同。WiFi的mac地址虽然不会变,但实际上某些配置也发生了变化,导致无论是使用有线连接还是无线连接,在每次重启后,连接ssh总会得到以下提示:
因此只能在连接前先输入清除keygen命令,再连接才行。目前不太清楚这个问题如何妥善解决,只能先用临时方案凑合。
- ssh-keygen -R 目标IP地址
- ssh root@目标IP地址
下面是邮件使用的介绍。
依旧,没有任何现成的库,我们只能用最基础的shell工具来实现接入smtp服务器发送邮件。由于固件并不支持expect命令,因此我们只能用简单粗暴的sleep方式来确保脚本可以在交互指令中正常工作:
- ip="smtp.qq.com 587"
- user="email in Base64"
- pass="app pwd in Base64"
- sender="xxx@qq.com"
- receiver="xxx@qq.com"
- subject="HELP"
- content="Please help me! Call xxxxxxxx"
- mail(){
- {
- sleep 1
- echo "helo test"
- sleep 1
- echo "auth login"
- sleep 1
- echo "$user"
- sleep 1
- echo "$pass"
- sleep 1
- echo "mail from:<$sender>"
- sleep 1
- echo "rcpt to:<$receiver>"
- sleep 1
- echo "data"
- sleep 1
- echo "from: $sender"
- echo "to: $receiver"
- echo "subject: $subject"
- echo ""
- echo "$content"
- echo "."
- sleep 1
- echo "quit"
- sleep 1
- }|telnet $ip >> /tmp/mail.log
- }
现在的邮箱要使用stmp登录都需要专用的app密码,这里大家自行去自己的邮箱中申请。需要注意的是,登陆中填入的邮箱地址和密码我们需要先转换为Base64再填入,不能直接明文填入。
填写好邮箱地址了密码后,将以上变量中的xxx都进行替换,之后运行一下这个函数,应该就可以看到邮箱中有正常收到邮件了。大家可以自行更改邮件的标题的内容。
至此,所有的功能都已成功实现。下面就是把所有的功能整合在一起,完成最终项目。
|