Retropie 设置中文

RetroPie复古游戏模拟系统设置中文

步骤简述

    1. 下载最新的Retropie镜像,别问我从哪里下载。
    1. 烧录到TF卡,也别问我怎么烧录。
    1. 开机启动后连wifi或者网络, 更别问我怎么连wifi。
    1. 进系统后直接按F4进入终端,在确保联网的情况下输入:
      sudo apt-get update 
      sudo apt-get -y install fonts-droid-fallback
      sudo reboot 

      然后你安装的游戏就算是有中文也没有问题了。

Linux 系统中用C语言调用串口

总览

不幸的是,在Linux中使用串行端口并不是世界上最简单的事情。在处理termios.h标头时,存在许多复杂的设置,这些设置隐藏在价值多个字节的位域中。该页面试图帮助解释这些设置,并向您展示如何在Linux中正确配置串行端口。

一切都是文件

在典型的UNIX风格中,串行端口由操作系统中的文件表示。这些文件通常会弹出/dev/,并以name开头tty*。

常用名称是:

  • /dev/ttyACM0-ACM代表USB总线上的ACM调制解调器。Arduino UNO(及类似名称)将使用此名称显示。
  • /dev/ttyPS0 -运行基于Yocto的Linux构建的Xilinx Zynq FPGA将使用此名称作为Getty连接到的默认串行端口。
  • /dev/ttyS0-标准COM端口将具有此名称。如今,由于较新的台式机和笔记本电脑没有实际的COM端口,这些情况已经不太普遍了。
  • /dev/ttyUSB0 -大多数USB到串行电缆将使用这样的文件显示。
  • /dev/pts/0-伪终端。这些可以通过生成socat。
    Linux和连接的Arduino的/dev/目录的列表。 Arduino串行端口显示为/dev/ttyACMO0。
    Linux和连接的Arduino的/dev/目录的列表。Arduino串行端口显示为/dev/ttyACMO0。

要写入串行端口,请写入文件。要从串行端口读取,请从文件读取。当然,这允许您发送/接收数据,但是如何设置串行端口参数,例如波特率,奇偶校验等?这是通过特殊tty配置设置的struct。

C语言的基本设置

  • 注意
    此代码也适用于C ++。
    首先,我们要包括一些内容:
// C library headers
#include <stdio.h>
#include <string.h>

// Linux headers
#include <fcntl.h> // Contains file controls like O_RDWR
#include <errno.h> // Error integer and strerror() function
#include <termios.h> // Contains POSIX terminal control definitions
#include <unistd.h> // write(), read(), close()
然后,我们要打开串行端口设备(在下方显示为文件/dev/),保存由返回的文件描述符open():

int serial_port = open("/dev/ttyUSB0", O_RDWR);

# Check for errors
if (serial_port < 0) {
    printf("Error %i from open: %s\n", errno, strerror(errno));
}

一个你可能会看到这里的常见错误是errno = 2,和strerror(errno)回报No such file or directory。确保您具有正确的设备路径,并且该设备存在!

您可能会在这里遇到的另一个常见错误errno = 13是Permission denied。这通常是因为当前用户不属于拨出组。使用以下命令将当前用户添加到拨出组:

$ sudo adduser $USER dialout

这些组更改生效之前,您必须先注销然后重新登录。
在这一点上,我们可以从技术上对串行端口进行读写,但是由于默认配置设置不是为串行端口设计的,因此它可能无法工作。因此,现在我们将正确设置配置。
修改任何配置值时,最佳做法是仅修改您感兴趣的位,而保留该字段的所有其他位。这就是为什么你会看到使用下面&=或者|=,从来没有&或|设置位时。

配置设置

我们需要访问该termios结构才能配置串行端口。我们将创建一个新termios结构,然后使用写入串行端口的现有配置tcgetattr(),然后根据需要修改参数并使用保存设置tcsetattr()。

// Create new termios struc, we call it 'tty' for convention
// No need for "= {0}" at the end as we'll immediately write the existing
// config to this struct
struct termios tty;

// Read in existing settings, and handle any error
if(tcgetattr(serial_port, &tty) != 0) {
    printf("Error %i from tcgetattr: %s\n", errno, strerror(errno));
}

现在,我们可以tty根据需要更改的设置,如以下各节所示。

控制模式(c_cflags)

该结构的c_cflags成员termios包含控制参数字段。

  • PARENB(平价)
    如果该位置1,则启用奇偶校验位的生成和检测。大多数串行通信不使用奇偶校验位,因此,如果不确定,请清除该位。
tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity (most common)
tty.c_cflag |= PARENB;  // Set parity bit, enabling parity

CSTOPB(数字停止位)
如果该位置1,则使用两个停止位。如果清除该位,则仅使用一个停止位。大多数串行通信仅使用一个停止位。

tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication (most common)
tty.c_cflag |= CSTOPB;  // Set stop field, two stop bits used in communication

每字节位数

该CS字段中设置多少个数据位,每个字节通过串行端口传输。此处最常见的设置是8(CS8)。如果不确定,请绝对使用此端口,在此之前我从未使用过未使用8的串行端口(但它们确实存在)。

tty.c_cflag |= CS5; // 5 bits per byte
tty.c_cflag |= CS6; // 6 bits per byte
tty.c_cflag |= CS7; // 7 bits per byte
tty.c_cflag |= CS8; // 8 bits per byte (most common)

流量控制(CRTSCTS)

如果CRTSCTS设置了该字段,则启用硬件RTS / CTS流控制。这里最常见的设置是禁用它。当应禁用此功能时启用它可能会导致您的串行端口不接收任何数据,因为发送方将无限期地对其进行缓冲,等待您“就绪”。

tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control (most common)
tty.c_cflag |= CRTSCTS;  // Enable RTS/CTS hardware flow control

CREAD和CLOCAL

设置CLOCAL将禁用调制解调器特定的信号线,例如载波检测。SIGHUP当检测到调制解调器断开连接时,还可以防止控制过程发送信号,这通常是一件好事。设置CLOCAL使我们能够读取数据(我们绝对想要!)。

tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1)

本地模式(c_lflag)

  • 禁用规范模式
    UNIX系统提供输入,的两种基本模式的规范和非规范模式。在规范模式下,当收到换行符时,将处理输入。接收应用程序逐行接收该数据。在处理串行端口时,这通常是不希望的,因此我们通常要禁用规范模式。

通过以下方式禁用了规范模式:

tty.c_lflag &= ~ICANON;

同样,在规范模式下,某些字符(例如退格键)会被特殊对待,并用于编辑当前文本行(擦除)。同样,我们不希望此功能处理原始串行数据,因为它将导致特定字节丢失!

ECHO

如果该位置1,发送的字符将被回显。因为我们禁用了规范模式,所以我认为这些位实际上没有任何作用,但是以防万一,以防万一!

tty.c_lflag &= ~ECHO; // Disable echo
tty.c_lflag &= ~ECHOE; // Disable erasure
tty.c_lflag &= ~ECHONL; // Disable new-line echo

禁用信号字符

当该ISIG位置1时INTR,QUIT和会SUSP被解释。我们不希望使用串行端口,因此请清除以下位:

tty.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP

输入模式(c_iflag)

该结构的c_iflag成员termios包含用于输入处理的低级设置。所述c_iflag构件是一个int。

软件流控制(IXOFF,IXON,IXANY)

结算IXOFF,IXON并IXANY禁用软件流控制,这是我们不想要的:

tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl

禁用接收时字节的特殊处理

清除以下所有位将禁用对字节的任何特殊处理,因为这些字节在被串行端口接收并传递给应用程序之前。我们只想要原始数据,谢谢!

tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); // Disable any special handling of received bytes

输出模式(c_oflag)

结构的c_oflag成员termios包含用于输出处理的低级设置。配置串行端口时,我们要禁用对输出字符/字节的任何特殊处理,因此请执行以下操作:

tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
// tty.c_oflag &= ~OXTABS; // Prevent conversion of tabs to spaces (NOT PRESENT IN LINUX)
// tty.c_oflag &= ~ONOEOT; // Prevent removal of C-d chars (0x004) in output (NOT PRESENT IN LINUX)

双方OXTABS并ONOEOT没有在Linux的定义。但是Linux确实具有XTABS似乎相关的领域。为Linux编译时,我只排除了这两个字段,并且串行端口仍然可以正常工作。

VMIN和VTIME(c_cc)

VMIN对于试图在Linux中配置串行端口的许多程序员来说,这VTIME是一个混乱的根源。

需要注意的重要一点是,VTIME根据内容的不同,含义也有所不同VMIN。当VMIN为0时,VTIME指定从read()调用开始的超时。但是当VMIN>> 0时,VTIME指定从第一个接收到的字符开始的超时时间。

让我们探索不同的组合:

  • VMIN = 0,VTIME = 0:无阻塞,立即返回可用值
  • VMIN> 0,VTIME = 0:这将read()始终等待字节(确切地由决定多少个字节VMIN),因此read()可以无限期地阻塞。
  • VMIN = 0,VTIME> 0:这是对最大超时(由给出VTIME)的任何数字字符的阻塞读取。read()将阻塞直到有大量数据可用或发生超时为止。这恰好是我最喜欢的模式(也是我最常使用的模式)。
  • VMIN> 0,VTIME> 0:阻塞直到VMIN接收到任何字符或VTIME第一个字符过去。请注意,VTIME直到收到第一个字符,超时才会开始。
  • VMIN和VTIME都定义为type cc_t,我一直看到它是unsigned char(1个字节)的别名。这使VMIN字符数的上限为255,最大超时为25.5秒(255分秒)。

“一旦收到任何数据,立即返回”并不意味着您一次只能得到1个字节。根据操作系统延迟,串行端口速度,硬件缓冲区以及您无法直接控制的许多其他因素,您可能会收到任意数量的字节。

例如,如果我们要等待最多1秒的时间,一旦收到任何数据就返回,我们可以使用:

tty.c_cc[VTIME] = 10;    // Wait for up to 1s (10 deciseconds), returning as soon as any data is received.
tty.c_cc[VMIN] = 0;

波特率

而不是使用位字段与所有其他设置,串口波特率是通过调用函数集cfsetispeed()和cfsetospeed(),传递的一个指针tty结构和enum:

// Set in/out baud rate to be 9600
cfsetispeed(&tty, B9600);
cfsetospeed(&tty, B9600);

如果要保持UNIX兼容,则必须从以下一项中选择波特率:

B0,  B50,  B75,  B110,  B134,  B150,  B200, B300, B600, B1200, B1800, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800

如果使用GNU C库进行编译,则可以放弃这些枚举,而直接指定整数波特率,例如:

// Specifying a custom baud rate when using GNU C
cfsetispeed(&tty, 104560);
cfsetospeed(&tty, 104560);

并非所有硬件都支持所有波特率,因此如果可以选择的话,最好坚持使用上述标准BXXX速率之一。如果您不知道波特率是多少,并且尝试与第三方系统通信,请尝试B9600,然后B57600再尝试,B115200因为它们是最常用的速率。

  • 有关Linux串行端口代码示例,请参见https://github.com/gbmhunter/CppLinuxSerial。

保存termios

更改这些设置后,我们可以使用以下命令保存ttytermios结构tcsetattr():

// Save tty settings, also checking for error
if (tcsetattr(serial_port, TCSANOW, &tty) != 0) {
    printf("Error %i from tcsetattr: %s\n", errno, strerror(errno));
}

读写

现在我们已经打开并配置了串行端口,我们可以对其进行读写了!

  • 写入
    通过该write()功能完成对Linux串行端口的写入。我们使用serial_port从open()上面的调用返回的文件描述符。
unsigned char msg[] = { 'H', 'e', 'l', 'l', 'o', '\r' };
write(serial_port, "Hello, world!", sizeof(msg));

读取

通过该read()功能进行读取。您必须为Linux提供缓冲区以将数据写入其中。

// Allocate memory for read buffer, set size according to your needs
char read_buf [256];

// Read bytes. The behaviour of read() (e.g. does it block?,
// how long does it block for?) depends on the configuration
// settings above, specifically VMIN and VTIME
int n = read(serial_port, &read_buf, sizeof(read_buf));

// n is the number of bytes read. n may be 0 if no bytes were received, and can also be negative to signal an error.

关闭串口

这很简单:

close(serial_port)

完整的例子

// C library headers
#include <stdio.h>
#include <string.h>

// Linux headers
#include <fcntl.h> // Contains file controls like O_RDWR
#include <errno.h> // Error integer and strerror() function
#include <termios.h> // Contains POSIX terminal control definitions
#include <unistd.h> // write(), read(), close()

// Open the serial port. Change device path as needed (currently set to an standard FTDI USB-UART cable type device)
int serial_port = open("/dev/ttyUSB0", O_RDWR);

// Create new termios struc, we call it 'tty' for convention
struct termios tty;

// Read in existing settings, and handle any error
if(tcgetattr(serial_port, &tty) != 0) {
    printf("Error %i from tcgetattr: %s\n", errno, strerror(errno));
}

tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity (most common)
tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication (most common)
tty.c_cflag |= CS8; // 8 bits per byte (most common)
tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control (most common)
tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1)

tty.c_lflag &= ~ICANON;
tty.c_lflag &= ~ECHO; // Disable echo
tty.c_lflag &= ~ECHOE; // Disable erasure
tty.c_lflag &= ~ECHONL; // Disable new-line echo
tty.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl
tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); // Disable any special handling of received bytes

tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
// tty.c_oflag &= ~OXTABS; // Prevent conversion of tabs to spaces (NOT PRESENT ON LINUX)
// tty.c_oflag &= ~ONOEOT; // Prevent removal of C-d chars (0x004) in output (NOT PRESENT ON LINUX)

tty.c_cc[VTIME] = 10;    // Wait for up to 1s (10 deciseconds), returning as soon as any data is received.
tty.c_cc[VMIN] = 0;

// Set in/out baud rate to be 9600
cfsetispeed(&tty, B9600);
cfsetospeed(&tty, B9600);

// Save tty settings, also checking for error
if (tcsetattr(serial_port, TCSANOW, &tty) != 0) {
    printf("Error %i from tcsetattr: %s\n", errno, strerror(errno));
}

// Write to serial port
unsigned char msg[] = { 'H', 'e', 'l', 'l', 'o', '\r' };
write(serial_port, "Hello, world!", sizeof(msg));

// Allocate memory for read buffer, set size according to your needs
char read_buf [256];

// Normally you wouldn't do this memset() call, but since we will just receive
// ASCII data for this example, we'll set everything to 0 so we can
// call printf() easily.
memset(&read_buf, '\0', sizeof(read_buf);

// Read bytes. The behaviour of read() (e.g. does it block?,
// how long does it block for?) depends on the configuration
// settings above, specifically VMIN and VTIME
int num_bytes = read(serial_port, &read_buf, sizeof(read_buf));

// n is the number of bytes read. n may be 0 if no bytes were received, and can also be -1 to signal an error.
if (num_bytes < 0) {
    printf("Error reading: %s", strerror(errno));
}

// Here we assume we received ASCII data, but you might be sending raw bytes (in that case, don't try and
// print it to the screen like this!)
printf("Read %i bytes. Received message: %s", num_bytes, read_buf);

close(serial_port)

getty的问题

如果getty试图管理tty要与之进行串行通信的同一设备,它可能会引起串行通信问题。

停止getty:

getty很难停止,因为默认情况下,如果您尝试杀死进程,那么新进程将立即启动。

这些说明适用于旧版本的Linux和/或嵌入式Linux。

加载/etc/inittab您喜欢的文本编辑器。
注释掉涉及getty到您的tty设备的所有行。
保存并关闭文件。
运行命令~$ init q以重新加载/etc/inittab文件。
终止设备上所有正在运行的getty进程tty。他们现在应该死了!

进程独立占用

最好尝试同时防止其他进程对串行端口进行读/写操作。
实现此目的的一种方法是使用flock()系统调用:

#include <sys/file.h>

int main() {

    // ... get file descriptor here

    // Acquire non-blocking exclusive lock
    if(flock(fd, LOCK_EX | LOCK_NB) == -1) {
        throw std::runtime_error("Serial port with file descriptor " + 
            std::to_string(fd) + " is already locked by another process.");
    }

    // ... read/write to serial port here
}

例子

有关Linux串行端口代码示例,请参见https://github.com/gbmhunter/CppLinuxSerial(请注意,该库是用C ++而不是C编写的)。

外部资源

有关结构配置参数的官方规范,请参见http://www.gnu.org/software/libc/manual/html_node/Terminal-Modes.htmltermios。

MySQL 小结

1. 备份数据库中的表。

1.1 选择备份路径,执行备份。

退出mysql客户端并切换到D盘,d:

mysqldump -u root -p employee > myemployee.sql

注: employee 是数据库名, myemployee.sql 是备份文件名
确认成功后,尝试删除数据库

2. 删除数据库

mysql -u root -p 
mysql> drop database 数据库名;
mysql> drop database employee;

3. 尝试恢复数据库。

3.1 先创建数据库

mysql -u root -p 
passwd: xxxxxx
mysql> create database employee;
mysql> exit
d:\> mysql -u root -p employee < myemployee.sql   还原数据库中的表
password: xxxxxx
d:\> mysql -u root -p 
password: xxxxxx
mysql> show databases;     显示数据库
mysql> use employee;     打开数据库
mysql> desc employee_tbl;   描述表结构
mysql> show tables;  显示表名

3.2 一条命令执行查询的方法:

D:\>mysql -u root -pzypxxx -e "use employee; select coalesce(name,'总数:'), SUM(signin) as sigin_total from employee_tbl group by name with rollup;"

4. 额外创建一个表user_into

mysql> use employee;
mysql> create table user_info (
-> `id`  int(11) NOT NULL, 
-> `name` varchar(10) NOT NULL DEFAULT '',
-> `age`  int(3) NOT NULL,
-> `sex`  varchar(2) NOT NULL,
-> `salary`  float(9,2) NOT NULL,
-> PRIMARY KEY(`id`));
mysql> insert into user_info values 
-> ('1', '小明', 23, '男', 5200.22),
-> ('2', '小王', 24, '男', 5300.22),
-> ('3', '小美', 26, '女', 6200.32);

5. 更新表结构

mysql>alter table user_info add column `Addr`  varchar(100) NOT NULL after `salary`;
mysql>update  user_info set Addr='奉贤紫屿培训学校' where name='小明';

6. 联合查询连接功能

mysql> select a.name, a.age, a.salary, b.signin from user_info a inner join employee_tbl b  on a.name=b.name;

7. 总结

  • 库操作: 增删改查
    增:create database 数据库名字;
    删:drop database 数据库名字;
    改: use 数据库名字; 打开数据库
    查:show databases;
  • 表操作: 增删改查
    增:create table 表名(字段名 字段类型 字段属性, 字段名2.....);

    create table aa (`id` int(10)  NOT NULL Auto_increment, `name` varchar(20) NOT NULL);

    删:drop table aa;
    改:alter table aa ADD COLUMN addr varchar(10) NOT NULL AFTER name;

    alter table  aa MODIFY COLUMN `salary` float(9,2);
    alter table  aa DEL COLUMN `addr`;
    改记录
    update  aa set salary=5300.33 where name='小明';

    查:desc aa; 查表结构
    查记录: select 字段1, 字段2 .... 字段N FROM 表名;

               select * from aa; 
               select * from aa where  id=1; 
               select * from aa order by id desc; 
               select * from aa order by id asc;
               select * from aa group by name;
               select name,  count(*) from aa group by name;
               select coalesce(name, "总数:"),  SUM(signin) from aa group by name with rollup;

    8.数据表的备份和还原

    8.1 备份数据库:

    mysqldump -u root -p 数据库名字  >  备份文件.sql

    8.2 还原数据表:

    mysql -u root -p -e "create database bbs;"
    mysql -u root -p bbs < 备份文件.sql

mysql -u root -p -e "create database bbs"
mysql -u root -p bbs < 备份文件.sql

树莓派4B跑个WS2812灯带

WS2812灯带在树莓派4B上的变化

今天尝试了一下,好多代码都变化了。
现在用的基本上就是要将树莓派的RPi.GPIO库都丢了。

sudo apt purge -y RPi.GPIO
sudo pip3 install rpi_ws281x adafruit-circuitpython-neopixel
sudo python3 -m pip install --force-reinstall adafruit-blinka

然后就安装这两个库够了。
灯带的5V接树莓派5V,当然,如果灯的数量多,建议额外供电,我就8个灯的灯带,够用。
GND接树莓派GND。
信号口D+接到树莓派物理接口12号,BCM的18号口上。
然后就可以写代码测试了。

import board
from time import sleep
import neopixel

pixels = neopixel.NeoPixel(board.D18, 8)

pixels.fill((0,255,0))

pixels[0] = (255,0,0)

while True:
    for x in range(0, 8):
        pixels[x] = (255, 0, 0)
        sleep(0.1)
        pixels.fill((0,255,0))

    for x in range(0, 8):
        pixels[x] = (255, 0, 0)
        sleep(0.1)
        pixels.fill((0,255,255))

    for x in range(0, 8):
        pixels[x] = (255, 0, 0)
        sleep(0.1)
        pixels.fill((0,0,255))

    for x in range(0, 8):
        pixels[x] = (0, 255, 0)
        sleep(0.1)
        pixels.fill((255,255,127))

    for x in range(0, 8):
        pixels[x] = (0, 255, 0)
        sleep(0.1)
        pixels.fill((255,255,0))

代码非常简单,不屑注释了。

import board
from time import sleep
import neopixel

pixels = neopixel.NeoPixel(board.D18, 8)

pixels.fill((0,255,0))

这段代码是初始化的部分。
运行以下代码以导入必要的模块,并初始化带有8个LED的NeoPixel灯带,如果你的NeoPixels连接到其他引脚,别忘了更改引脚,如果灯的数量不一样,也要改。
实例化后我用了fill方法来做操作了,有三个方法如下:

  • brightness - The overall brightness of the LED
  • fill - Color all pixels a given color.
  • show - Update the LED colors if auto_write is set to False.
    一般brightness是调亮度,fill就是填充颜色,show更新颜色。

    pixels[0] = (255,0,0)

    file
    就是点亮第一个灯,颜色为红色,(255,0,0) 就是 (R,G,B)三色的定义,每个灯都可以由3种颜色组合成N多种颜色,自己配置。

    pixels.fill((0, 255, 0))

    就是全部填充绿色。
    file
    就这么简单,其他自己琢磨吧。
    哦,最后给一张特写图:
    file
    file



    嗯,就这样。开心去浪吧!

树莓派串口编程

树莓派串口编程

简单做个笔记记录一下串口编程的方法。

  1. 树莓派需要释放蓝牙所占用的的串口。
  2. 编辑/boot/config.txt 或者通过raspi-config启用串口(serial) ,编辑文件的话直接加入enable_uart=1 然后重启。
  3. 添加 dtoverlay = pi3-miniuart-bt 或者:dtoverlay = pi3-disable-bt

    基本思路

    操作示例代码

    • C 语言
      #include <stdio.h>
      #include <string.h>
      #include <errno.h>
      #include <wiringPi.h>
      #include <wiringSerial.h>
      int main ()
      {
      int serial_port ;
      char dat;
      if ((serial_port = serialOpen ("/dev/ttyS0", 9600)) < 0) /* open serial port */
      {
      fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
      return 1 ;
      }
      if (wiringPiSetup () == -1)                   /* initializes wiringPi setup */
      {
      fprintf (stdout, "Unable to start wiringPi: %s\n", strerror (errno)) ;
      return 1 ;
      }
      while(1){   
      if(serialDataAvail (serial_port) )
      { 
      dat = serialGetchar (serial_port);      /* receive character serially*/ 
      printf ("%c", dat) ;
      fflush (stdout) ;
      serialPutchar(serial_port, dat);        /* transmit character serially on port */
        }
      }
      }

      编译测试

      gcc -o serialtest -lwiringPi serialtest.c 
      ./serialtest

      结果:

ESP32测试脚本

ESP32 测试脚本

Micropython

from machine import Pin
from time import sleep

leds = [13, 12, 14, 27, 26, 25, 33, 32, 23, 22, 21, 19, 18, 5, 16, 17, 4, 0, 2, 15 ]
try:
    while True:
        for i in range(len(leds)):
            print(leds[i])
            i = Pin(leds[i], Pin.OUT)
            i.on()
except KeyboardInterrupt:
    print("\nCtrl-C pressed.")

树莓派超声波测距

树莓派超声波测距

超声波传感器

就是传说中的Ultrasonic传感器,学名:HC-SR04 , 某宝上非常cheap, 自己搜.

测距原理

  • 超声波距离传感器设计为使用超声波来测量源与目标之间的距离。
  • 我们之所以使用超声波,是因为超声波在短距离内相对准确,并且不会引起人耳无法听到的干扰。

特性说明

HC-SR04是用于2cm至400cm距离非接触距离测量的常用模块。
它使用声纳(如蝙蝠和海豚)以高精度和稳定的读数来测量距离。
它由超声波发射器,接收器和控制电路组成。
发射器发射短脉冲,该短脉冲被目标反射并被接收器拾取。
计算超声波信号的发送和接收之间的时间差。
使用声速和“ 速度=距离/时间 ”等式,可以轻松计算源与目标之间的距离。

引脚说明

HC-SR04超声波距离传感器模块具有四个引脚:

  • VCC – 5V,输入电源

  • TRIG –触发输入

  • 回声 –回声输出

  • GND –接地

    实际工作原理

  • 1.向TRIG输入提供触发信号,它需要至少10μS持续时间的高电平信号。

  • 2.这使模块能够发送八个40KHz超声波脉冲串。

  • 3.如果模块前面有障碍物,它将反射那些超声波

  • 4.如果信号返回,则模块的ECHO输出将在发送和接收超声信号所花费的时间内保持为高电平。脉冲宽度的范围为150μS至25mS,具体取决于障碍物与传感器之间的距离,如果没有障碍物,则脉冲宽度约为38ms。

    接线方式

    非常关键的分压步骤

    ECHO输出为5v而Raspberry Pi GPIO的输入引脚的额定电压为3.3V,因此,无法将5V直接提供给不受保护的3.3V输入引脚,除非你想把树莓派干掉...
    因此,我们得使用分压电路,使用适当的电阻将电压降至3.3V。

    以下公式可用于计算电阻值,
    “ Vout = Vin x R2 /(R1 + R2)”
    这里我用的是常用的4.7K和10K电阻做的分压电路,中间抽头给树莓派GPIO引脚,安全可靠。

    连接实物模拟图

    画图软件是frizing, 不要再私信问我了...

    计算方法

  • 距离计算
    脉冲所花费的时间实际上是超声波信号往返的时间,而我们只需要一半的时间。因此,时间被视为时间/ 2。

  • 距离=速度时间/ 2
    而海平面声速= 343 m / s或34300 cm / s
    因此,距离= 17150
    时间(单位厘米)

*校准
为了获得准确的距离读数,可以使用尺子校准输出。在下面的程序中,添加了0.5 cm的校准。
你如果不想校准也可以尝试不加,就是大致有点儿偏移量。

测试代码:

import RPi.GPIO as GPIO                    #Import GPIO library
import time                                #Import time library
GPIO.setmode(GPIO.BCM)                     #Set GPIO pin numbering 

TRIG = 23                                  #Associate pin 23 to TRIG
ECHO = 24                                  #Associate pin 24 to ECHO

print "Distance measurement in progress"

GPIO.setup(TRIG,GPIO.OUT)                  #Set pin as GPIO out
GPIO.setup(ECHO,GPIO.IN)                   #Set pin as GPIO in

while True:

  GPIO.output(TRIG, False)                 #Set TRIG as LOW
  print "Waitng For Sensor To Settle"
  time.sleep(2)                            #Delay of 2 seconds

  GPIO.output(TRIG, True)                  #Set TRIG as HIGH
  time.sleep(0.00001)                      #Delay of 0.00001 seconds
  GPIO.output(TRIG, False)                 #Set TRIG as LOW

  while GPIO.input(ECHO)==0:               #Check whether the ECHO is LOW
    pulse_start = time.time()              #Saves the last known time of LOW pulse

  while GPIO.input(ECHO)==1:               #Check whether the ECHO is HIGH
    pulse_end = time.time()                #Saves the last known time of HIGH pulse 

  pulse_duration = pulse_end - pulse_start #Get pulse duration to a variable

  distance = pulse_duration * 17150        #Multiply pulse duration by 17150 to get distance
  distance = round(distance, 2)            #Round to two decimal points

  if distance > 2 and distance < 400:      #Check whether the distance is within range
    print "Distance:",distance - 0.5,"cm"  #Print distance with 0.5 cm calibration
  else:
    print "Out Of Range"                   #display out of range

测试

python3 ultrasonic_distance_detect.py

效果很明显。

总结

反射角度如果大于15度有可能会出现值不准,如果附近噪声很大也许会有干扰,其他的没啥,很简单的一个模块,可以结合树莓派或者别的设备做一个超声波控制音量的玩意儿,树莓派爬音乐网站,播放音乐,由超声波传感器来进行检测,距离小于多少就降低音量,否则就开大音量, 自己想办法玩儿吧! 转载记得标识出处!
谢谢观看,我是骑驴玩儿漂移,甩你三条街~ 白了个白~

Live555直播

树莓派上用 Live555 直播摄像头数据

最近在群里听到有朋友推荐使用 live555 来在树莓派上进行rtsp 服务器的搭建,非常简单做个记录防忘记.
Live555是一个开源的 C++源码编写的流媒体推流软件合集,功能好多,还咩有玩儿透彻,但是你也看得懂源码的.非常激动人心.

软件包下载

链接: http://www.live555.com/liveMedia/public/

通过命令解压并执行 makefile 的生成.

tar -xf live555-latest.tar.gz
cd live/
./genMakefiles linux

编辑当前目录下面的live/testProgs/testOnDemandRTSPServer.cpp

修改这部分内容:

树莓派上创建一个 fifo 文件,先进先出管道.

mkfifo /tmp/rpicam

然后编译并安装.

make 
sudo make install

进入 testProgs 目录执行二进制文件.

./testOnDemandRTSPServer &

树莓派开启摄像头并执行:

raspivid -rot 180 -o /tmp/rpicam -f -t 0

VLC 测试或者 opencv 测试:

  1. vlc 在打开网络流的URL 里面输入设备流地址: rtsp://192.168.3.20:8554/liv0 就可以观看了.
  2. 使用 opencv 打开,自己创建一个文件:
    如图,截图中缩进层级有点儿变化,主要看后面的代码.
    图为:

    代码走一波

    # get streaming video via opencv
    import cv2
    import numpy as np
    cap = cv2.VideoCapture("rtsp://192.168.3.20:8554/liv0")
    try:
    while True:
        ret, frame = cap.read()
        if ret == True:
            smallFrame = cv2.resize(frame, (480, 240))
    
            key = cv2.waitKey(1)
            if key == 27:
                break
            cv2.imshow("small size Frame", smallFrame)
    except KeyboardInterrupt:
    print("quit")
    cap.release()
    cv2.destroyAllWindows()

    执行查看:

    python3 streaming_get_from_opencv.py

    效果如图:

    好了,还有一个我在蘑菇云参加一个 piday4fun 的活动地址在: https://github.com/piday4fun

    还楞啥,燥起来吧!!!

    转发记得标明出处, 否则小心菊花万人捅~

KiCAD 第一弹: 小白入门级

KiCAD

缘起

自从安装了 KiCAD 以后,突然发现这是一个非常棒的开源软件,好多的资源可以用,内心激动的迫不及待的想做出一个 PCB 板.手头还有一片 ATmega328P-AU 的 arduino 芯片,赶紧搜索了一下 arduino 的最小系统原理图,照猫画虎来了一遍.其实还是有多小细节要注意的.

其实发现还是有 arduino Uno 的一个器件的.还需要慢慢摸索.这次的硬核马拉松我觉得我要败了..

发现

树莓派上竟然也可以跑 kicad, 而且安装极其简单,简单的不像话....

sudo apt-get update 
sudo apt-get -y install kicad
kicad &

就好了.就打开了,第一次可能有点儿卡顿,但是一旦跑起来那种丝般柔顺的感觉真的很舒服~
突然就爱上了这个软件.虽然相比 AD 可能还有很大差距,但是毕竟是开源软件,还有那么多用户,github 也是人气满满.强烈推荐大家尝试一下..
我发现我需要学习的东西太多了,我一直感觉自己是一个小白一样的存在, 看了很多资料还是前面看完后面就不记得了....
哎,人到中年不如狗系列啊!
好了,不吐槽了.还是要有满满的正能量才可以, 继续啃啃技术材料吧~
我是骑驴玩儿漂移,一个胖胖的爱玩儿树莓派或者是喜欢嘚瑟的胖纸!

抗击疫情宅家充电系列-树莓派编程基础

抗击疫情宅家充电系列

今天受邀在电子森林,哦,应该是硬禾学堂做了树莓派的入门级讲解,昨天也做了一个硬件讲解的直播,使用的软件是小鹅通,感觉还不错,有兴趣的朋友可以尝试一下.

下面是直播的地址:

第一天内容

树莓派上安装Opencv遇到的小bug解决方法

前言

最近很多人用树莓派跑opencv,我之前也用过,后来最近突然迷上了openCV的应用,就烧录了最新的系统,然后重新安装了opencv的环境,测试的时候发现加载不进来。
提示:

pi@raspberrypi:~ $ python3
Python 3.7.3 (default, Apr  3 2019, 05:39:12) 
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/pi/cv2/__init__.py", line 3, in <module>
    from .cv2 import *
ImportError: /home/pi/cv2/cv2.cpython-37m-arm-linux-gnueabihf.so: undefined symbol: __atomic_fetch_add_8

提示找到不到cv2.cpython-37m-arm-linux-gnueabihf.so 一个未定义的__atomic_fetch_add_8, 搜了一下发现github上面有官方的issue,里面说这个是一个bug, 难怪很多人抱怨安装不来opencv呢。
其实只需要加载一下一个库文件就好了。

LD_PRELOAD=/usr/lib/arm-linux-gnueabihf/libatomic.so.1

把这一条加载到/etc/bashrc 或者 /etc/profile文件里面就好了,我是直接加载到pi用户的初始化脚本里面了。

vim.tiny .bashrc
添加:export LD_PRELOAD=/usr/lib/arm-linux-gnueabihf/libatomic.so.1 

保存,退出。

source .bashrc

然后进入python3的环境再测试。

小bug解决了,每次开机也都不用担心了。

ffmpeg小技巧总结

ffmpeg强大的爆,直接记录一些使用小技巧。

视频转换

比如avi文件想转mp4,或者mp4想转为ts。

ffmpeg -i test.avi output.mp4
ffmpeg -i test.mp4 output.ts

如果想指定解码方式,比如h265可以使用libx264

ffmpeg -i test.avi -vcodec libx264 output.mp4

直接获取网络上的视频,自动下载并且转码并保存,该方式需要带上-y,按顺序读取

ffmpeg -i "http://www.yoyojacky.com/video/test.avi" -y -vcodec libx264 output.mp4

分离并提取音频存为AAC格式

ffmpeg -i test.mp4 -acodec copy -vn output.aac

默认mp4的audio codec是aac,如果不是,可以都转为最常见的aac,苹果手机支持,想做铃声的自己可以抓视频然后采集声音。

ffmpeg -i test.mp4 -acodec aac -vn output.aac

提取视频

ffmpeg -i test.mp4 -vcodec copy -an output.mp4

视频截图

ffmpeg -i test.mp4 -r 1 -q:v 2 -f image2 snapshot.jpg

-r 表示每一秒几帧
-q:v表示存储jpg的图像质量,一般2是高质量。
这条命令ffmpeg会把test.mp4,每隔一秒,存一张图片下来。假设有60s,那会有60张。
如果你想,也可以设置开始的时间,和你想要截取的时间。

ffmpeg -i test.mp4 -ss 00:00:30 -t 20 -r 1 -q:v 2 -f image2 pic-1.jpg

-ss 表示开始时间
-t 表示共要多少时间。
以上的命令,ffmpeg会从test.mp4的第30s时间开始,往下20s,即30~50s这20秒钟之间,每隔1s就抓一帧,总共会抓20帧。

视频剪切

下面的命令,可以从时间为00:00:45开始,截取10秒钟的视频。

ffmpeg -ss 00:00:45 -t 00:00:10 -i test.mp4 -vcodec copy -acodec copy output.mp4

-ss表示开始切割的时间,-t表示要切多少。上面就是从45秒开始,截取10秒钟的视频。

码率控制

码率控制对于在线视频比较重要,因为在线视频需要考虑带宽。
那么什么是码率?so easy:
bitrate = file size / duration
比如一个文件20.8M,时长1分钟,那么,码率就是:
biterate = 20.8M bit/60s = 20.810241024*8 bit/60s= 2831Kbps
一般音频的码率只有固定几种,比如是128Kbps,
那么,video的就是
video biterate = 2831Kbps -128Kbps = 2703Kbps。

 那么ffmpeg如何控制码率?

ffmpg控制码率有3种选择:-minrate -b:v -maxrate
-b:v主要是控制平均码率。
比如一个视频源的码率太高了,有10Mbps,文件太大,想把文件弄小一点,但是又不破坏分辨率。

ffmpeg -i test.mp4 -b:v 2000k output.mp4

上面把码率从原码率转成2Mbps码率,这样其实也间接让文件变小了,目测接近一半。
不过,ffmpeg官方wiki比较建议,设置b:v时,同时加上 -bufsize
-bufsize 用于设置码率控制缓冲器的大小,设置的好处是,让整体的码率更趋近于希望的值,减少波动。(简单来说,比如1 2的平均值是1.5, 1.49 1.51 也是1.5, 当然是第二种比较好)

ffmpeg -i test.mp4 -b:v 2000k -bufsize 2000k output.mp4

-minrate -maxrate就简单了,在线视频有时候,希望码率波动不要超过一个阈值,可以设置maxrate。

ffmpeg -i test.mp4 -b:v 2000k -bufsize 2000k -maxrate 2500k output.mp4

视频编码格式转换

比如一个视频的编码是MPEG4,想用H264编码,咋办?

ffmpeg -i test.mp4 -vcodec h264 output.mp4

相反也一样

ffmpeg -i test.mp4 -vcodec mpeg4 output.mp4

当然了,如果ffmpeg当时编译时,添加了外部的x265或者X264,那也可以用外部的编码器来编码。(不知道什么是X265,可以 Google一下,简单的说,就是她不包含在ffmpeg的源码里,是独立的一个开源代码,用于编码HEVC,ffmpeg编码时可以调用它。当然 了,ffmpeg自己也有编码器)

ffmpeg -i test.mp4 -c:v libx265 output.mp4 
ffmpeg -i test.mp4 -c:v libx264 output.mp4

将视频进行m3u8切片

ffmpeg -i 本地视频.ts -c copy -map 0 -f segment -segment_list 视频索引.m3u8 -segment_time 5 前缀-%03d.ts

其中segment 就是切片,-segment_time表示隔几秒进行切一个文件,上面命令是隔5s,你也可以调整成更大的参数。
上面是网上抄的,下面是我经常用的:

ffmpeg -i test.mp4 -c copy hls_list_size 0 output.m3u8 hls_time 5

上面的hls_list_size表示目录文件中需要播放的文件数量,0表示整个视频,hls_time表示每个切片的长度,上面设置的5秒

只提取视频ES数据

ffmpeg –i test.mp4 –vcodec copy –an –f m4v output.h264

过滤器的使用

动态设置视频分辨率

将输入的1920x1080缩小到800:600输出:

ffmpeg -i test.mp4 -vf scale=800:600 output.mp4

ps: 如果600不写,写成-1,即scale=800:-1, 那也是可以的,ffmpeg会通知缩放滤镜在输出时保持原始的宽高比。

ffmpeg -i input.mp4 -vf scale=800:-1 output.mp4

为视频添加logo

比如我有一个图片想要贴到一个视频上:

ffmpeg -i test.mp4 -i logo.png -filter_complex overlay output.mp4
####要贴到其他地方?看下面: 
右上角: 
```bash
ffmpeg -i test.mp4 -i logo.png -filter_complex overlay=W-w output.mp4

左下角:

ffmpeg -i test.mp4 -i logo.png -filter_complex overlay=0:H-h output.mp4

右下角:

ffmpeg -i input.mp4 -i logo.png -filter_complex overlay=W-w:H-h output.mp4

去掉视频的logo

语法:-vf delogo=x:y:w:h[:t[:show]]
x:y 离左上角的坐标
w:h logo的宽和高
t: 矩形边缘的厚度默认值4
show:若设置为1有一个绿色的矩形,默认值0。

ffmpeg -i test.mp4 -vf delogo=0:0:220:90:100:1 output.mp4 

序列帧与视频的相互转换

把test.[001-100].jpg序列帧和music.mp3音频文件利用mpeg4编码方式合成视频文件test.avi:

ffmpeg -i music.mp3 -i test.%3d.jpg -s 800x600 -author yoyo -vcodec mpeg4 test.avi

还可以把视频文件导出成jpg序列帧:

ffmpeg -i test.avi pic.%d.jpg

好了,后面有空继续添加小技巧。

树莓派配置 vim 支持 python 代码补全

首先在树莓派中安装vim:

sudo apt-get update
sudo apt-get install vim  

克隆rkulla 的pydiction项目到本地:

mkdir -p ~/.vim/bundle
cd ~/.vim/bundle
git clone https://github.com/rkulla/pydiction.git
cp -r ~/.vim/bundle/pydiction/after/ ~/.vim   # 这步非常关键

如果有新的软件包想要支持补全.例如 RPi.GPIO
那么先安装包

sudo apt-get -y install RPi.GPIO

然后进入目录
cd ~/.vim/bundle/pydiction/
python3 pydiction.py RPi.GPIO
就可以生成全新的 complete-dict 了.

配置.vimrc文件:
" 启用文件类型插件

filetype plugin on

" 配置pydiction插件路径

let g:pydiction_location = '~/.vim/bundle/pydiction/complete-dict'

" 设置pydiction补全菜单的高度,默认是8

let g:pydiction_menu_height = 20
set syntax on

国庆节学习小计

今天下班开始就进入了十一小长假的状态,但是内心里面忐忑不安的是,太多事情要处理了,没有一天可以闲着.真的很累.
明天要去嘉定,非常远,昨天 3 点多才睡觉,生活不规律,但也没办法,就像现在我还在查资料一样.

搭建在阿里云的个人博客也应为 mysql 数据库服务器的日志塞满导致了宕机,由于开启了秘钥登陆,在公司还无法操作,眼睁着看着也无计可施.
刚才维护了一下,其实阿里云的平台也还不错,最近也试了试 azure iot 的平台,感觉更加成熟和稳定. 未来的物联网 Demo 还是要在这个平台上多做做测试.

明天一天忙碌完,就可以好好休息了.
假期安排:

  1. 继续写书
  2. 整理家里的东西,该扔的扔了,该卖的卖了.保持轻装前行
  3. 假期可以好好看看书,打打篮球
  4. 减肥减肥,继续减肥
  5. 陪老婆做做计划,干点儿有意义的事情.
  6. 把构想的电路图画完.
  7. 优化雷达小车的代码.