入坑树莓派-05-红外遥控

入坑树莓派-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

然后使用遥控器的重启键重启机器后,就能愉快地用用遥控器控制屏幕了。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注