入坑树莓派-05-红外遥控
1.遥控测试
扩展板上有个红外遥控模块:
为了测试这个模块,我把孩子国学机上的遥控器拿过来了(其实随便找一个红外遥控器就行):
运行下面的代码:
#include <bcm2835.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// gcc -o irm irm.c -lbcm2835
#define IRM_PIN 18
int main()
{
if (!bcm2835_init())
return 1;
bcm2835_gpio_fsel(IRM_PIN, BCM2835_GPIO_FSEL_INPT);
bcm2835_gpio_set_pud(IRM_PIN, BCM2835_GPIO_PUD_UP);
unsigned char i,idx,cnt;
unsigned char count;
unsigned char data[4];
while (1)
{
if (bcm2835_gpio_lev(IRM_PIN) != 0)
{
usleep(1000);
continue;
}
count = 0;
while (bcm2835_gpio_lev(IRM_PIN) == 0 && count++ < 200) //9ms
delayMicroseconds(60);
count = 0;
while (bcm2835_gpio_lev(IRM_PIN) == 1 && count++ < 80) //4.5ms
delayMicroseconds(60);
idx = 0;
cnt = 0;
data[0]=0;
data[1]=0;
data[2]=0;
data[3]=0;
for (i = 0; i < 32; i++)
{
count = 0;
while (bcm2835_gpio_lev(IRM_PIN) == 0 && count++ < 15) //0.56ms
delayMicroseconds(60);
count = 0;
while (bcm2835_gpio_lev(IRM_PIN) == 1 && count++ < 40) //0: 0.56ms; 1: 1.69ms
delayMicroseconds(60);
if (count > 25)
data[idx] |= (1<<cnt);
if (cnt== 7)
{
cnt=0;
idx++;
}
else
cnt++;
}
if ((data[0]+data[1] == 0xFF) && (data[2]+data[3]==0xFF))
{
printf("0x%02x\n",data[2]);
}
}
bcm2835_close();
return 0;
}
然后随便按下遥控器的几个按键,屏幕上就会输出相关的按键码了:
理论上,我们写个switch语句,收到特定的按键码后执行相应的操作,就能实现用遥控器控制做一些实际操作了。
2.遥控功能
问题1:红外遥控接收程序是个C程序,控制屏幕的是个python程序,怎么实现两个程序的联动呢?
最简单的方法是弄一个中间的文件,C程序将收到的按键码写入,python程序读取文件中的按键码,显示对应的屏幕信息。
我们准备自定义一下这几个按键:
代码如下:
#include <bcm2835.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// gcc -o irmscreen irmscreen.c -lbcm2835
#define IRM_PIN 18
void key_cmd(unsigned char key_val)
{
switch(key_val)
{
case 0x45://关机
system("echo 99 > /root/board/product/screen.txt");
break;
case 0x58://重启
system("echo 98 > /root/board/product/screen.txt");
break;
case 0x0c://按键1
system("echo 1 > /root/board/product/screen.txt");
break;
case 0x18://按键2
system("echo 2 > /root/board/product/screen.txt");
break;
case 0x5e://按键3
system("echo 3 > /root/board/product/screen.txt");
break;
case 0x08://按键4
system("echo 4 > /root/board/product/screen.txt");
break;
case 0x1c://按键5
system("echo 5 > /root/board/product/screen.txt");
break;
case 0x5a://按键6
system("echo 6 > /root/board/product/screen.txt");
break;
case 0x42://按键7
system("echo 7 > /root/board/product/screen.txt");
break;
case 0x52://按键8
system("echo 8 > /root/board/product/screen.txt");
break;
case 0x4a://按键9
system("echo 9 > /root/board/product/screen.txt");
break;
default:
break;
}
}
int main()
{
if (!bcm2835_init())
return 1;
bcm2835_gpio_fsel(IRM_PIN, BCM2835_GPIO_FSEL_INPT);
bcm2835_gpio_set_pud(IRM_PIN, BCM2835_GPIO_PUD_UP);
unsigned char i,idx,cnt;
unsigned char count;
unsigned char data[4];
while (1)
{
if (bcm2835_gpio_lev(IRM_PIN) != 0)
{
usleep(1000);
continue;
}
count = 0;
while (bcm2835_gpio_lev(IRM_PIN) == 0 && count++ < 200) //9ms
delayMicroseconds(60);
count = 0;
while (bcm2835_gpio_lev(IRM_PIN) == 1 && count++ < 80) //4.5ms
delayMicroseconds(60);
idx = 0;
cnt = 0;
data[0]=0;
data[1]=0;
data[2]=0;
data[3]=0;
for (i = 0; i < 32; i++)
{
count = 0;
while (bcm2835_gpio_lev(IRM_PIN) == 0 && count++ < 15) //0.56ms
delayMicroseconds(60);
count = 0;
while (bcm2835_gpio_lev(IRM_PIN) == 1 && count++ < 40) //0: 0.56ms; 1: 1.69ms
delayMicroseconds(60);
if (count > 25)
data[idx] |= (1<<cnt);
if (cnt== 7)
{
cnt=0;
idx++;
}
else
cnt++;
}
if ((data[0] + data[1] == 0xFF) && (data[2] + data[3] == 0xFF))
{
// printf("key: 0x%02x\n",data[2]);
key_cmd(data[2]);
}
}
bcm2835_close();
return 0;
}
然后修改屏幕展示的python代码,如下:
import sys
import time
import busio
import socket
import fcntl
import struct
import board
import subprocess
import Adafruit_DHT
import adafruit_ssd1306
from board import SCL, SDA
from PIL import Image, ImageDraw, ImageFont
font_cn = ImageFont.truetype('/root/board/fonts/微软雅黑.ttf', 20)
font_en = ImageFont.truetype('/root/board/fonts/Courier_New.ttf', 14)
def get_ip_address(ifname):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
return socket.inet_ntoa(fcntl.ioctl(
s.fileno(),
0x8915, # SIOCGIFADDR
struct.pack('256s', str.encode(ifname[:15]))
)[20:24])
def show_screen_welcom():
oled.fill(0)
image = Image.new('1', (oled.width, oled.height))
draw = ImageDraw.Draw(image)
draw.text((0, 0), '欢迎页面', font=font_cn, fill=255)
oled.image(image)
oled.show()
def show_screen_ip():
oled.fill(0)
WIFIADDR = ""
WIREADDR = ""
try:
WIFIADDR += get_ip_address('wlan0')
except IOError:
WIFIADDR += "0.0.0.0"
try:
WIREADDR += get_ip_address('eth0')
except IOError:
WIREADDR += "0.0.0.0"
image = Image.new('1', (oled.width, oled.height))
draw = ImageDraw.Draw(image)
draw.text((0, 10), WIFIADDR, font=font_en, fill=255)
draw.text((0, 30), WIREADDR, font=font_en, fill=255)
oled.image(image)
oled.show()
def show_screen_time():
oled.fill(0)
image = Image.new('1', (oled.width, oled.height))
draw = ImageDraw.Draw(image)
draw.text((0, 0), time.strftime("%A"), font=font_en, fill=255)
draw.text((0, 20), time.strftime("%Y-%m-%d"), font=font_en, fill=255)
draw.text((0, 40), time.strftime("%X"), font=font_en, fill=255)
oled.image(image)
oled.show()
def show_screen_stats():
oled.fill(0)
image = Image.new('1', (oled.width, oled.height))
draw = ImageDraw.Draw(image)
cmd = "top -bn1 | grep load | awk '{printf \"%.2f\", $(NF-2)}'"
cpustr = subprocess.check_output(cmd, shell=True).decode("utf-8")
cmd = "free -m | awk 'NR==2{printf \"%s MB\", $3 }'"
memstr = subprocess.check_output(cmd, shell=True).decode("utf-8")
cmd = "df -h | awk '$NF==\"/\"{printf \"%d GB\", $3}'"
diskstr = subprocess.check_output(cmd, shell=True).decode("utf-8")
cmd = "expr `cat /sys/class/thermal/thermal_zone0/temp` / 1000"
tempstr = subprocess.check_output(cmd, shell=True).decode("utf-8")
draw.text((0, 0), "CPU: " + cpustr, font=font_en, fill=255)
draw.text((0, 14), "MEM: " + memstr, font=font_en, fill=255)
draw.text((0, 28), "DSK: " + diskstr, font=font_en, fill=255)
draw.text((0, 44), "TMP: " + tempstr, font=font_en, fill=255)
oled.image(image)
oled.show()
def show_screen_climate():
oled.fill(0)
image = Image.new('1', (oled.width, oled.height))
draw = ImageDraw.Draw(image)
humistr, tempstr = Adafruit_DHT.read_retry(Adafruit_DHT.DHT11, 4)
draw.text((0, 0), '温度 : {0:0.1f}度'.format(tempstr), font=font_cn, fill=255)
draw.text((0, 20), '湿度 : {0:0.1f}%'.format(humistr), font=font_cn, fill=255)
oled.image(image)
oled.show()
def show_screen_cpufreq():
oled.fill(0)
image = Image.new('1', (oled.width, oled.height))
draw = ImageDraw.Draw(image)
cmd = "expr `cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq` / 1000"
cpu0str = subprocess.check_output(cmd, shell=True).decode("utf-8")
cmd = "expr `cat /sys/devices/system/cpu/cpu1/cpufreq/scaling_cur_freq` / 1000"
cpu1str = subprocess.check_output(cmd, shell=True).decode("utf-8")
cmd = "expr `cat /sys/devices/system/cpu/cpu2/cpufreq/scaling_cur_freq` / 1000"
cpu2str = subprocess.check_output(cmd, shell=True).decode("utf-8")
cmd = "expr `cat /sys/devices/system/cpu/cpu3/cpufreq/scaling_cur_freq` / 1000"
cpu3str = subprocess.check_output(cmd, shell=True).decode("utf-8")
draw.text((0, 0), "CPU0 : " + cpu0str, font=font_en, fill=255)
draw.text((0, 15), "CPU1 : " + cpu1str, font=font_en, fill=255)
draw.text((0, 30), "CPU2 : " + cpu2str, font=font_en, fill=255)
draw.text((0, 45), "CPU3 : " + cpu3str, font=font_en, fill=255)
oled.image(image)
oled.show()
def show_screen_help(helpstr):
oled.fill(0)
image = Image.new('1', (oled.width, oled.height))
draw = ImageDraw.Draw(image)
draw.text((0, 0), helpstr, font=font_cn, fill=255)
oled.image(image)
oled.show()
i2c = busio.I2C(SCL, SDA)
oled = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c)
func = 0
while True:
cmd = "cat /root/board/product/screen.txt"
func = subprocess.check_output(cmd, shell=True).decode("utf-8")
match int(func):
case 1:
show_screen_welcom()
case 2:
show_screen_ip()
case 3:
show_screen_time()
case 4:
show_screen_stats()
case 5:
show_screen_climate()
case 6:
show_screen_cpufreq()
case 98:
cmd = 'echo 1 > /root/board/product/screen.txt'
subprocess.call(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
show_screen_help("重启了")
cmd = 'reboot'
subprocess.call(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
case 99:
show_screen_help("关机了")
cmd = 'echo 1 > /root/board/product/screen.txt'
subprocess.call(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
cmd = 'poweroff'
subprocess.call(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
case _:
show_screen_help("指令不支持")
time.sleep(1)
最后,我们把这两个程序变成开机启动:
cd /etc/systemd/system
vim oledshow.service
增加代码如下:
[Unit]
Description=oledshow
[Service]
ExecStart=/usr/bin/python /root/board/product/oledshow.py
[Install]
WantedBy=default.target
然后:
vim irmscreen.service
增加代码如下:
[Unit]
Description=irmscreen
[Service]
ExecStart=/root/board/product/irmscreen
[Install]
WantedBy=default.target
设置服务开机自动启动:
systemctl daemon-reload
systemctl enable oledshow
systemctl start oledshow
systemctl enable irmscreen
systemctl start irmscreen
然后使用遥控器的重启键重启机器后,就能愉快地用用遥控器控制屏幕了。