Linux GPIO can be controlled via the sysfs interface by navigating to the /sys/class/gpio directory.
export: Used to export a GPIO pin with a specified number. Before using a GPIO pin, it needs to be exported. Once successfully exported, it can be used.
unexport: Used to remove an exported GPIO pin. After using a GPIO pin, we need to remove the exported pin. Writing the specified number into the export file will export the GPIO pin with that number, and after a successful export, a corresponding gpioX (X indicates the GPIO number) will be created under the /sys/class/gpio directory.
direction: Configures the GPIO pin as input or output. This file is both readable and writable; reading it shows whether the GPIO is currently set as input or output, and writing to it sets the GPIO as input or output. The acceptable values for read or write operations are "out" (output mode) and "in" (input mode).
value: When the GPIO is configured as output, writing "0" to the value file sets the GPIO output to low, while writing "1" sets it to high. In input mode, reading the value file retrieves the current input level of the GPIO pin.
active_low: This attribute file is used to control polarity and is both readable and writable.
edge: Controls the interrupt trigger mode. This file is readable and writable. Before configuring the interrupt trigger mode of a GPIO pin, it should be set to input mode:
Non-interrupt pin: echo "none" > edge
Rising edge trigger: echo "rising" > edge
Falling edge trigger: echo "falling" > edge
Both edge trigger: echo "both" > edge
The Rockchip GPIO corresponding user-space GPIO numbers are shown in the table below.
| GPIO | GPIO Number |
|---|---|
| GPIO0_B0 | 8 |
| GPIO2_C0 | 80 |
| GPIO4_C3 | 147 |
| GPIO0_C5 | 21 |
| GPIO4_C4 | 148 |
| GPIO4_C5 | 149 |
| GPIO2_B2 | 74 |
| GPIO2_B1 | 73 |
cd /sys/class/gpio/
# Change the file owner to youyeetoo
sudo chown youyeetoo:youyeetoo export
sudo chown youyeetoo:youyeetoo unexport
# Using GPIO0_B0 as an example to operate GPIO output, other GPIO operations can be exported according to the correspondence in the previous table.
# Export GPIO0_B0
echo 8 > export
# Change the file owner to youyeetoo
sudo chown youyeetoo:youyeetoo gpio8/direction
sudo chown youyeetoo:youyeetoo gpio8/value
cd gpio8
# Set Output
echo out > direction
# Output high level
echo 1 > value
# Output low level
echo 0 > value
# Unexport GPIO pin
cd ..
echo 8 > unexport
vim gpio_output.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
static char gpio_path[32];
static int gpio_config(const char *attr, const char *val)
{
char file_path[64];
int len;
int fd;
sprintf(file_path, "%s/%s", gpio_path, attr);
fd = open(file_path, O_WRONLY);
if (fd < 0) {
perror("open error");
return fd;
}
len = strlen(val);
if (len != write(fd, val, len)) {
perror("write error");
close(fd);
return -1;
}
close(fd); //Close file
return 0;
}
int main(int argc, char *argv[])
{
int fd;
int len;
/* Validate parameters */
if (argc != 3) {
fprintf(stderr, "usage: %s <gpio> <value>\n", argv[0]);
return -1;
}
/* Check if the specified GPIO number is exported */
sprintf(gpio_path, "/sys/class/gpio/gpio%s", argv[1]);
//If the directory does not exist, it needs to be exported.
if (access(gpio_path, F_OK)) {
fd = open("/sys/class/gpio/export", O_WRONLY);
if (fd < 0) {
perror("open error");
return -1;
}
len = strlen(argv[1]);
//Export GPIO
if (len != write(fd, argv[1], len)) {
perror("write error");
close(fd);
return -1;
}
close(fd); //Close file
}
/* Configure as output mode */
if (gpio_config("direction", "out")) return -1;
/* Polarity Settings */
if (gpio_config("active_low", "0")) return -1;
/* Control GPIO output high and low levels */
if (gpio_config("value", argv[2])) return -1;
close(fd);
/* Exit program */
return 0;
}
gcc gpio_output.c -o gpio_output
# Output high level
sudo ./gpio_output 8 1
# Output low level
sudo ./gpio_output 8 0
cd /sys/class/gpio/
# Change the file owner to youyeetoo
sudo chown youyeetoo:youyeetoo export
sudo chown youyeetoo:youyeetoo unexport
# Using GPIO0_B0 as an example to operate GPIO output, other GPIO operations can be exported according to the corresponding relationships in the previous table.
# Export GPIO0_B0
echo 8 > export
# Change the file owner to youyeetoo
sudo chown youyeetoo:youyeetoo gpio8/direction
sudo chown youyeetoo:youyeetoo gpio8/value
cd gpio8
# Set Input
echo in > direction
# Check GPIO level
cat value
# Remove exported GPIO pin
cd ..
echo 8 > unexport
vim gpio_input.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
static char gpio_path[32];
static int gpio_config(const char *attr, const char *val)
{
char file_path[64];
int len;
int fd;
sprintf(file_path, "%s/%s", gpio_path, attr);
if (0 > (fd = open(file_path, O_WRONLY))) {
perror("open error");
return fd;
}
len = strlen(val);
if (len != write(fd, val, len)) {
perror("write error");
close(fd);
return -1;
}
close(fd); //Close file
return 0;
}
int main(int argc, char *argv[])
{
char file_path[64];
char val;
int fd;
int len;
/* Validate parameters */
if (argc != 2) {
fprintf(stderr, "usage: %s <gpio>\n", argv[0]);
return -1;
}
/* Check if the specified GPIO number is exported */
sprintf(gpio_path, "/sys/class/gpio/gpio%s", argv[1]);
// If the directory does not exist, it needs to be exported
if (access(gpio_path, F_OK)) {
if ((fd = open("/sys/class/gpio/export", O_WRONLY)) < 0) {
perror("open error");
return -1;
}
len = strlen(argv[1]);
// Export GPIO
if (len != write(fd, argv[1], len)) {
perror("write error");
close(fd);
return -1;
}
close(fd); //Close file
}
/* Configure as input mode */
if (gpio_config("direction", "in")) return -1;
/* Polarity Settings */
if (gpio_config("active_low", "0")) return -1;
/* Configured for non-interrupt mode */
if (gpio_config("edge", "none")) return -1;
/* Read GPIO voltage level */
sprintf(file_path, "%s/%s", gpio_path, "value");
if ((fd = open(file_path, O_RDONLY)) < 0) {
perror("open error");
return -1;
}
if (read(fd, &val, 1) < 0) {
perror("read error");
close(fd);
return -1;
}
printf("value: %c\n", val);
/* Exit program */
close(fd);
return 0;
}
Compile and run, read the GPIO pin level
gcc gpio_input.c -o gpio_input
sudo ./gpio_input 8
vim gpio_irq.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <poll.h>
static char gpio_path[32];
static int gpio_config(const char *attr, const char *val)
{
char file_path[64];
int len;
int fd;
sprintf(file_path, "%s/%s", gpio_path, attr);
fd = open(file_path, O_WRONLY);
if (fd < 0) {
perror("open error");
return fd;
}
len = strlen(val);
if (len != write(fd, val, len)) {
perror("write error");
return -1;
}
close(fd); //Close file
return 0;
}
int main(int argc, char *argv[])
{
struct pollfd pfd;
char file_path[64];
int ret;
char val;
int len;
int fd;
/* Validate parameters */
if (argc != 2) {
fprintf(stderr, "usage: %s <gpio>\n", argv[0]);
return -1;
}
/* Check if the specified GPIO number is exported */
sprintf(gpio_path, "/sys/class/gpio/gpio%s", argv[1]);
// If the directory does not exist, it needs to be exported
if (access(gpio_path, F_OK)) {
fd = open("/sys/class/gpio/export", O_WRONLY);
if (fd < 0) {
perror("open error");
return -1;
}
len = strlen(argv[1]);
// Export GPIO
if (len != write(fd, argv[1], len)) {
perror("write error");
return -1;
}
close(fd); //Close file
}
/* Configure as input mode */
if (gpio_config("direction", "in")) return -1;
/* Polarity Settings */
if (gpio_config("active_low", "0")) return -1;
/* Configure interrupt trigger mode: rising edge and falling edge */
if (gpio_config("edge", "both")) return -1;
/* Open the value attribute file */
sprintf(file_path, "%s/%s", gpio_path, "value");
pfd.fd = open(file_path, O_RDONLY);
if (pfd.fd < 0) {
perror("open error");
return -1;
}
/* Call poll */
pfd.events = POLLPRI; //Only care about high-priority data being readable (interrupt)
read(pfd.fd, &val, 1); // First, read once to clear the status
while (1) {
ret = poll(&pfd, 1, -1); //Call poll
if (ret < 0) {
perror("poll error");
return -1;
} else if (ret == 0) {
fprintf(stderr, "poll timeout.\n");
continue;
} else {
/* Check if high-priority data is readable */
if(pfd.revents & POLLPRI) {
if (lseek(pfd.fd, 0, SEEK_SET) < 0) { //Move the read position to the head
perror("lseek error");
return -1;
}
if (read(pfd.fd, &val, 1) < 0) {
perror("read error");
return -1;
}
printf("GPIO Interrupt Trigger <value=%c>\n", val);
}
}
}
/* Exit program */
return 0;
}
Compile and run
gcc gpio_irq.c -o gpio_irq
sudo ./gpio_irq
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
int set_opt(int,int,int,char,int);
void main(){
int fd,nByte;
char *uart3 = "/dev/ttyS2";
char bufferR[2];
char bufferW[2];
memset(bufferR, '\0', 2);
memset(bufferW, '\0', 2);
if((fd=open(uart3,O_RDWR,0777))<0)
{
printf("failed\n");
}
else{
printf("success\n");
set_opt(fd, 115200, 8, 'N', 1);
}
while(1){
nByte = 0;
memset(bufferR, '\0', 2);
memset(bufferW, '\0', 2);
// printf("hello\n");
if((nByte = read(fd, bufferR, 1)) == 1){ //MCU serial send and receive functions are all single-byte (single-character) functions
printf("receive:%c\n",bufferR[0]);
bufferW[0] = 'A';
write(fd,bufferW,1); //Send a single byte (single character) via serial port
buffer[0] = data
memset(bufferR, '\0', 2);
memset(bufferW, '\0', 2);
nByte = 0;
}
}
close(fd);
}
// General serial port initialization function
int set_opt(int fd,int nSpeed, int nBits, char nEvent, int nStop)
{
struct termios newtio,oldtio;// Define the structs newtio and oldtio
//Get the data from the original serial port into oldtio
if ( tcgetattr( fd,&oldtio) != 0) {
perror("SetupSerial 1");
return -1;
}
//Clear newio and set c_cflag
bzero( &newtio, sizeof( newtio ) );
newtio.c_cflag |= CLOCAL | CREAD; //Enable receiving and ignoring control lines
newtio.c_cflag &= ~CSIZE;
// Set data bits
switch( nBits )
{
case 7:
newtio.c_cflag |= CS7;
break;
case 8:
newtio.c_cflag |= CS8;
break;
}
// Set checksum bit
switch( nEvent )
{
// Even parity
case 'O':
newtio.c_cflag |= PARENB;//Enable parity check
newtio.c_cflag |= PARODD;//Parity Check
newtio.c_iflag |= (INPCK | ISTRIP);// Input validation and ignore the eighth digit
break;
case 'E':
newtio.c_iflag |= (INPCK | ISTRIP);
newtio.c_cflag |= PARENB;
newtio.c_cflag &= ~PARODD;//Disable even parity (set even parity bit to zero), enable odd parity
break;
case 'N':
newtio.c_cflag &= ~PARENB;//No parity check
break;
}
// Set baud rate
switch( nSpeed )
{
case 2400:
cfsetispeed(&newtio, B2400);
cfsetospeed(&newtio, B2400);
break;
case 4800:
cfsetispeed(&newtio, B4800);
cfsetospeed(&newtio, B4800);
break;
case 9600:
cfsetispeed(&newtio, B9600);
cfsetospeed(&newtio, B9600);
break;
case 115200:
cfsetispeed(&newtio, B115200);
cfsetospeed(&newtio, B115200);
break;
case 460800:
cfsetispeed(&newtio, B460800);
cfsetospeed(&newtio, B460800);
break;
default:
cfsetispeed(&newtio, B9600);
cfsetospeed(&newtio, B9600);
break;
}
//Set stop bits
if( nStop == 1 )
newtio.c_cflag &= ~CSTOPB;// A stop bit
else if ( nStop == 2 )
newtio.c_cflag |= CSTOPB;//Two stop bits
newtio.c_cc[VTIME] = 0;// Do not set read timeout
newtio.c_cc[VMIN] = 0; // Read minimum number of characters as 0
tcflush(fd,TCIFLUSH); //Clear the buffer
// Make the configuration take effect
if((tcsetattr(fd,TCSANOW,&newtio))!=0)
{
perror("com set error");
return -1;
}
// printf("set done!\n\r");
return 0;
}
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
/* The device node of the I2C controller corresponding to the EEPROM */
#define EEPROM_DEVICE "/dev/i2c-0"
/* I2C device address of the EEPROM */
#define EEPROM_ADDR 0x50
/* Function name: eeprom_write
** Function: Write data to EEPROM
** Parameters: fd: the filename of the I2C controller device node corresponding to the EEPROM
** dev_addr: the I2C slave address of the EEPROM
** reg_addr: the register address of the EEPROM
** data_buf: the data buffer to write to the EEPROM
** len: the number of bytes to write. In this example, the current maximum supported is 8 bytes
** Return value: negative indicates operation failure, others indicate success
*/
int eeprom_write(int fd, unsigned char dev_addr, unsigned char reg_addr, unsigned char * data_buf,int len)
{
int ret;
unsigned char msg_buf[9];
struct i2c_rdwr_ioctl_data data;
struct i2c_msg messages;
/* 1. Construct msg_buf */
/* 1.1. Assign the starting address of the register to be operated to the first byte of data for I2C communication */
msg_buf[0] = reg_addr;
/* 1.2. Assign the data buffer to be written to the EEPROM after the EEPROM register in I2C data communication */
if (len < 9) { /* This demo supports writing up to 8 bytes of data to one page of the EEPROM at a time */
memcpy((void *) &msg_buf[1], data_buf, len); //Data after the first position
} else {
printf("This function supports up to 8 bytes at a time !!!\n");
return -1;
}
/* 2. Construct struct i2c_msg messages */
/* 2.1. Assign the I2C slave address of the EEPROM */
messages.addr = dev_addr;
/* 2.2. Assign flags to indicate that the I2C communication has completed the write operation */
messages.flags = 0;
/* 2.3. Assign len as the length of the data buf, the data length at the EEPROM register address */
messages.len = len+1;
/* 2.4. Build the data buffer for the message packet */
messages.buf = msg_buf;
/* 3. Construct struct i2c_rdwr_ioctl_data data */
/* 3.1. Assign the prepared message packets to the msgs field in i2c_rdwr_ioctl_data */
data.msgs = &messages;
/* 3.2. Since this I2C communication only involves a write operation, the number of messages is 1 */
data.nmsgs = 1;
/* 4. Call the driver layer's read-write combined I2C data transfer */
if(ioctl(fd, I2C_RDWR, &data) < 0)
{
printf("I2C_RDWR err \n");
return -1;
}
/* 5. Wait for the I2C bus write to complete */
sleep(1);
return 0;
}
/*Function name: eeprom_read
**Function: Read data from EEPROM
**Parameters: fd: The file name of the I2C controller device corresponding to the EEPROM
** dev_addr: The I2C slave address of the EEPROM
** reg_addr: The register address of the EEPROM
** data_buf: Buffer to store data read from the EEPROM
** len: Number of bytes to read.
**Return value: Negative value indicates operation failure, others indicate success
*/
int eeprom_read(int fd, unsigned char dev_addr, unsigned char reg_addr, unsigned char * data_buf,int len)
{
int ret;
unsigned char msg_buf[9];
struct i2c_rdwr_ioctl_data data;
struct i2c_msg messages[2];
/* 1. Construct struct i2c_msg messages */
/* 1.1. Construct the first message messages[0] */
/* 1.1.1. Assign the I2C slave device address of the EEPROM */
messages[0].addr = dev_addr;
/* 1.1.2. Assign flags to indicate that this I2C communication has completed the write operation */
messages[0].flags = 0;
/* 1.1.3. Assign len as 1 for the data length at the EEPROM register address */
messages[0].len = 1;
/* 1.1.4. The data for this action needs to read the starting address of the EEPROM register */
messages[0].buf = ®_addr;
/* 1.2. Construct the second message messages[1] */
/* 1.2.1. Assign the EEPROM I2C slave address */
messages[1].addr = dev_addr;
/* 1.1.2. Assign flags to indicate that this I2C communication has completed the read operation */
messages[1].flags = I2C_M_RD;
/* 1.1.3. Assign len as the length of data to read from the EEPROM register */
messages[1].len = len;
/* 1.1.4. The buffer location where the data for this read operation should be stored */
messages[1].buf = data_buf;
/* 2. Construct struct i2c_rdwr_ioctl_data data */
/* 2.1. Assign the prepared message packets to the msgs field in i2c_rdwr_ioctl_data */
data.msgs = messages;
/* 2.2. Since this I2C communication involves both write and read operations, the number of messages is 2 */
data.nmsgs = 2;
/* 3. Call the driver layer's read-write combined I2C data transfer */
if(ioctl(fd, I2C_RDWR, &data) < 0)
{
printf("I2C_RDWR err \n");
return -1;
}
/* 4. Wait for the I2C bus read to complete */
sleep(1);
return 0;
}
int main()
{
int fd,i,ret=0;
unsigned char w_add=0x10;
/* The data buffer to be read */
unsigned char rd_buf[8] = {0};
/* The data buffer to write */
unsigned char wr_buf[8] = {0};
printf("hello,this is I2C_RDWR i2c test \n");
/* Open the I2C controller file corresponding to the EEPROM */
fd =open(EEPROM_DEVICE, O_RDWR);
if (fd< 0)
{
printf("open"EEPROM_DEVICE"failed \n");
}
/* Write the data to be written into the following buf */
for(i=0;i<8;i++)
wr_buf[i]=i;
/* Read data from EEPROM using I2C_RDWR */
eeprom_write(fd,EEPROM_ADDR,w_add,wr_buf,8);
/* Write data to EEPROM using I2C_RDWR */
eeprom_read(fd,EEPROM_ADDR,w_add,rd_buf,8);
for(i=0;i<8;i++)
{
printf("rd_buf is :%d\n",rd_buf[i]);
}
/* After completing the operation, close the device file of the I2C controller corresponding to the EEPROM */
close(fd);
return 0;
}
CAN发送应用程序示例
/* 1. 报文发送程序 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
int main()
{
int s, nbytes;
struct sockaddr_can addr;
struct ifreq ifr;
struct can_frame frame[2] = {{0}};
s = socket(PF_CAN, SOCK_RAW, CAN_RAW);//创建套接字
strcpy(ifr.ifr_name, "can0" );
ioctl(s, SIOCGIFINDEX, &ifr); //指定 can0 设备
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
bind(s, (struct sockaddr *)&addr, sizeof(addr));//将套接字与 can0 绑定
//禁用过滤规则,本进程不接收报文,只负责发送
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
//生成两个报文
frame[0].can_id = 0x11;
frame[0]. can_dlc = 1;
frame[0].data[0] = 'Y';
frame[1].can_id = 0x22;
frame[1]. can_dlc = 1;
frame[1].data[0] = 'N';
//循环发送两个报文
while(1)
{
nbytes = write(s, &frame[0], sizeof(frame[0])); //发送 frame[0]
if(nbytes != sizeof(frame[0]))
{
printf("Send Error frame[0]\n!");
break; //发送错误,退出
}
sleep(1);
nbytes = write(s, &frame[1], sizeof(frame[1])); //发送 frame[1]
if(nbytes != sizeof(frame[0]))
{
printf("Send Error frame[1]\n!");
break;
}
sleep(1);
}
close(s);
return 0;
}
CAN接收程序示例
/* 2. 报文过滤接收程序 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
int main()
{
int s, nbytes;
struct sockaddr_can addr;
struct ifreq ifr;
struct can_frame frame;
struct can_filter rfilter[1];
s = socket(PF_CAN, SOCK_RAW, CAN_RAW); //创建套接字
strcpy(ifr.ifr_name, "can0" );
ioctl(s, SIOCGIFINDEX, &ifr); //指定 can0 设备
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
bind(s, (struct sockaddr *)&addr, sizeof(addr)); //将套接字与 can0 绑定
//定义接收规则,只接收表示符等于 0x11 的报文
rfilter[0].can_id = 0x11;
rfilter[0].can_mask = CAN_SFF_MASK;
//设置过滤规则
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
while(1)
{
nbytes = read(s, &frame, sizeof(frame)); //接收报文
//显示报文
if(nbytes > 0)
{
printf(“ID=0x%X DLC=%d data[0]=0x%X\n”, frame.can_id,
frame.can_dlc, frame.data[0]);
}
}
close(s);
return 0;
}
OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库。由一系列 C函数和少量 C++ 类构成,同时提供了 Python、Java、MATLAB 等语言的接口。
pkg-config --modversion opencv4
本系统默认内置版本为4.13.0。
mkdir OpenCV_Demo
cd OpenCV_Demo
mkdir build image src
cmake_minimum_required(VERSION 3.8)
project( OpenCV_Demo )
find_package( OpenCV REQUIRED )
include_directories( ${OpenCV_INCLUDE_DIRS} )
add_executable( image_demo src/image_demo.cpp )
add_executable( video_demo src/video_demo.cpp )
add_executable( camera_demo src/camera_demo.cpp )
target_link_libraries( image_demo ${OpenCV_LIBS} )
target_link_libraries( video_demo ${OpenCV_LIBS} )
target_link_libraries( camera_demo ${OpenCV_LIBS} )
#include <opencv2/opencv.hpp>
#include <iostream>
int main(int argc, char** argv) {
// 读取图片
cv::Mat image = cv::imread("../image/image.png");
// 确认图片读取成功
if(image.empty()) {
std::cerr << "Failed to open image file." << std::endl;
return -1;
}
//控制照片比例
resize(image, image, cv::Size(1280, 720));
// 显示图片
cv::imshow("Image with Box", image);
// 等待按键
cv::waitKey(0);
return 0;
}
#include <opencv2/opencv.hpp>
using namespace cv;
int main() {
// 打开视频文件
VideoCapture cap("../image/video.mp4");
// 检查视频是否成功打开
if (!cap.isOpened()) {
std::cout << "Error opening video stream or file" << std::endl;
return -1;
}
// 循环读取视频帧
while (true) {
Mat frame;
// 读取当前帧
cap >> frame;
// 检查是否成功读取帧
if (frame.empty())
break;
// 显示当前帧
imshow("Frame", frame);
// 按下 Esc 键退出循环
if (waitKey(25) == 27)
break;
}
// 释放VideoCapture对象和所有窗口
cap.release();
destroyAllWindows();
return 0;
}
#include <opencv2/opencv.hpp>
#include <iostream>
#include <string>
using namespace std;
using namespace cv;
int main() {
// 打开默认摄像头
VideoCapture cap(41);
if (!cap.isOpened()) {
cout << "无法打开摄像头!" << endl;
return -1;
}
namedWindow("摄像头", WINDOW_NORMAL);
while (true) {
Mat frame;
cap >> frame;
// 显示视频帧
imshow("摄像头", frame);
// 按下空格键拍照
if (waitKey(30) == ' ')
{
// 生成文件名
time_t now = time(NULL);
tm *ltm = localtime(&now);
string filename = to_string(ltm->tm_year + 1900) + "-" + to_string(ltm->tm_mon + 1) + "-" + to_string(ltm->tm_mday) + "-" + to_string(ltm->tm_hour) + "-" + to_string(ltm->tm_min) + "-" + to_string(ltm->tm_sec) + ".jpg";
// 保存图片
imwrite(filename, frame);
cout << "已保存照片:" << filename << endl;
}
}
return 0;
}
cd build
cmake ..
make
./image_demo
./video_demo
./camera_demo

pkg-config --modversion rockchip_mpp
pkg-config --modversion rockchip_vpu
git clone https://github.com/rockchip-linux/mpp.git
在下载的mpp目录里面 test目录,里面是一些mpp官方调用例程,用户可参考test目录和doc文档目录。
这里参考 test/mpi_dec_test.c 例程编写
vim mpp_dec_test.c
在官方例程中的头文件和在gcc编译时指定连接库。
源码如下
#define MODULE_TAG "mpp_dec_test"
#include <string.h>
#include <rockchip/rk_mpi.h>
#include <rockchip/mpp_mem.h>
#include <rockchip/mpp_env.h>
#include <rockchip/mpp_time.h>
#include <rockchip/mpp_common.h>
#include <rockchip/mpi_dec_utils.h>
typedef struct {
MpiDecTestCmd *cmd;
MppCtx ctx;
MppApi *mpi;
RK_U32 quiet;
/* end of stream flag when set quit the loop */
RK_U32 loop_end;
/* input and output */
DecBufMgr buf_mgr;
MppBufferGroup frm_grp;
MppPacket packet;
MppFrame frame;
FILE *fp_output;
RK_S32 frame_count;
RK_S32 frame_num;
RK_S64 first_pkt;
RK_S64 first_frm;
size_t max_usage;
float frame_rate;
RK_S64 elapsed_time;
RK_S64 delay;
FILE *fp_verify;
FrmCrc checkcrc;
} MpiDecLoopData;
static int dec_simple(MpiDecLoopData *data)
{
RK_U32 pkt_done = 0;
RK_U32 pkt_eos = 0;
MPP_RET ret = MPP_OK;
MpiDecTestCmd *cmd = data->cmd;
MppCtx ctx = data->ctx;
MppApi *mpi = data->mpi;
MppPacket packet = data->packet;
FileBufSlot *slot = NULL;
RK_U32 quiet = data->quiet;
FrmCrc *checkcrc = &data->checkcrc;
// when packet size is valid read the input binary file
ret = reader_read(cmd->reader, &slot);
mpp_assert(ret == MPP_OK);
mpp_assert(slot);
pkt_eos = slot->eos;
if (pkt_eos) {
if (data->frame_num < 0 || data->frame_num > data->frame_count) {
mpp_log_q(quiet, "%p loop again\n", ctx);
reader_rewind(cmd->reader);
pkt_eos = 0;
} else {
mpp_log_q(quiet, "%p found last packet\n", ctx);
data->loop_end = 1;
}
}
mpp_packet_set_data(packet, slot->data);
mpp_packet_set_size(packet, slot->size);
mpp_packet_set_pos(packet, slot->data);
mpp_packet_set_length(packet, slot->size);
// setup eos flag
if (pkt_eos)
mpp_packet_set_eos(packet);
do {
RK_U32 frm_eos = 0;
RK_S32 times = 30;
// send the packet first if packet is not done
if (!pkt_done) {
ret = mpi->decode_put_packet(ctx, packet);
if (MPP_OK == ret) {
pkt_done = 1;
if (!data->first_pkt)
data->first_pkt = mpp_time();
}
}
// then get all available frame and release
do {
RK_S32 get_frm = 0;
MppFrame frame = NULL;
try_again:
ret = mpi->decode_get_frame(ctx, &frame);
if (MPP_ERR_TIMEOUT == ret) {
if (times > 0) {
times--;
msleep(1);
goto try_again;
}
mpp_err("%p decode_get_frame failed too much time\n", ctx);
}
if (ret) {
mpp_err("%p decode_get_frame failed ret %d\n", ret, ctx);
break;
}
if (frame) {
if (mpp_frame_get_info_change(frame)) {
RK_U32 width = mpp_frame_get_width(frame);
RK_U32 height = mpp_frame_get_height(frame);
RK_U32 hor_stride = mpp_frame_get_hor_stride(frame);
RK_U32 ver_stride = mpp_frame_get_ver_stride(frame);
RK_U32 buf_size = mpp_frame_get_buf_size(frame);
MppBufferGroup grp = NULL;
mpp_log_q(quiet, "%p decode_get_frame get info changed found\n", ctx);
mpp_log_q(quiet, "%p decoder require buffer w:h [%d:%d] stride [%d:%d] buf_size %d",
ctx, width, height, hor_stride, ver_stride, buf_size);
if (MPP_FRAME_FMT_IS_FBC(cmd->format)) {
MppFrame frm = NULL;
mpp_frame_init(&frm);
mpp_frame_set_width(frm, width);
mpp_frame_set_height(frm, height);
mpp_frame_set_fmt(frm, cmd->format);
ret = mpi->control(ctx, MPP_DEC_SET_FRAME_INFO, frm);
mpp_frame_deinit(&frm);
if (ret) {
mpp_err("set fbc frame info failed\n");
break;
}
}
grp = dec_buf_mgr_setup(data->buf_mgr, buf_size, 24, cmd->buf_mode);
/* Set buffer to mpp decoder */
ret = mpi->control(ctx, MPP_DEC_SET_EXT_BUF_GROUP, grp);
if (ret) {
mpp_err("%p set buffer group failed ret %d\n", ctx, ret);
break;
}
data->frm_grp = grp;
/*
* All buffer group config done. Set info change ready to let
* decoder continue decoding
*/
ret = mpi->control(ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);
if (ret) {
mpp_err("%p info change ready failed ret %d\n", ctx, ret);
break;
}
} else {
char log_buf[256];
RK_S32 log_size = sizeof(log_buf) - 1;
RK_S32 log_len = 0;
RK_U32 err_info = mpp_frame_get_errinfo(frame);
RK_U32 discard = mpp_frame_get_discard(frame);
if (!data->first_frm)
data->first_frm = mpp_time();
log_len += snprintf(log_buf + log_len, log_size - log_len,
"decode get frame %d", data->frame_count);
if (mpp_frame_has_meta(frame)) {
MppMeta meta = mpp_frame_get_meta(frame);
RK_S32 temporal_id = 0;
mpp_meta_get_s32(meta, KEY_TEMPORAL_ID, &temporal_id);
log_len += snprintf(log_buf + log_len, log_size - log_len,
" tid %d", temporal_id);
}
if (err_info || discard) {
log_len += snprintf(log_buf + log_len, log_size - log_len,
" err %x discard %x", err_info, discard);
}
mpp_log_q(quiet, "%p %s\n", ctx, log_buf);
data->frame_count++;
if (data->fp_output && !err_info)
dump_mpp_frame_to_file(frame, data->fp_output);
if (data->fp_verify) {
calc_frm_crc(frame, checkcrc);
write_frm_crc(data->fp_verify, checkcrc);
}
fps_calc_inc(cmd->fps);
}
frm_eos = mpp_frame_get_eos(frame);
mpp_frame_deinit(&frame);
get_frm = 1;
}
// try get runtime frame memory usage
if (data->frm_grp) {
size_t usage = mpp_buffer_group_usage(data->frm_grp);
if (usage > data->max_usage)
data->max_usage = usage;
}
// if last packet is send but last frame is not found continue
if (pkt_eos && pkt_done && !frm_eos) {
msleep(1);
continue;
}
if (frm_eos) {
mpp_log_q(quiet, "%p found last packet\n", ctx);
break;
}
if ((data->frame_num > 0 && (data->frame_count >= data->frame_num)) ||
((data->frame_num == 0) && frm_eos))
break;
if (get_frm)
continue;
break;
} while (1);
if ((data->frame_num > 0 && (data->frame_count >= data->frame_num)) ||
((data->frame_num == 0) && frm_eos)) {
data->loop_end = 1;
break;
}
if (pkt_done)
break;
/*
* why sleep here:
* mpi->decode_put_packet will failed when packet in internal queue is
* full,waiting the package is consumed .Usually hardware decode one
* frame which resolution is 1080p needs 2 ms,so here we sleep 1ms
* * is enough.
*/
msleep(1);
} while (1);
return ret;
}
static int dec_advanced(MpiDecLoopData *data)
{
MPP_RET ret = MPP_OK;
MpiDecTestCmd *cmd = data->cmd;
MppCtx ctx = data->ctx;
MppApi *mpi = data->mpi;
MppPacket packet = NULL;
MppPacket packet_ret = NULL;
MppFrame frame = data->frame;
MppFrame frame_ret = NULL;
MppMeta meta = NULL;
RK_U32 quiet = data->quiet;
FileBufSlot *slot = NULL;
FrmCrc *checkcrc = &data->checkcrc;
ret = reader_index_read(cmd->reader, 0, &slot);
mpp_assert(ret == MPP_OK);
mpp_assert(slot);
mpp_packet_init_with_buffer(&packet, slot->buf);
// setup eos flag
if (slot->eos)
mpp_packet_set_eos(packet);
/* use the MppFrame with prealloced buffer and do not release */
meta = mpp_packet_get_meta(packet);
if (meta)
mpp_meta_set_frame(meta, KEY_OUTPUT_FRAME, frame);
ret = mpi->decode_put_packet(ctx, packet);
if (ret) {
mpp_err("%p mpp decode put packet failed ret %d\n", ctx, ret);
data->loop_end = 1;
goto DONE;
}
if (!data->first_pkt)
data->first_pkt = mpp_time();
ret = mpi->decode_get_frame(ctx, &frame_ret);
if (ret || !frame_ret) {
mpp_err("%p mpp decode get frame failed ret %d frame %p\n", ctx, ret, frame_ret);
data->loop_end = 1;
goto DONE;
}
if (!data->first_frm)
data->first_frm = mpp_time();
if (frame_ret != frame)
mpp_err_f("mismatch frame %p -> %p\n", frame_ret, frame);
/* write frame to file here */
if (data->fp_output)
dump_mpp_frame_to_file(frame_ret, data->fp_output);
if (data->fp_verify) {
calc_frm_crc(frame_ret, checkcrc);
write_frm_crc(data->fp_verify, checkcrc);
}
mpp_log_q(quiet, "%p decoded frame %d\n", ctx, data->frame_count);
data->frame_count++;
if (mpp_frame_get_eos(frame_ret))
mpp_log_q(quiet, "%p found eos frame\n", ctx);
fps_calc_inc(cmd->fps);
meta = mpp_frame_get_meta(frame);
if (meta) {
ret = mpp_meta_get_packet(meta, KEY_INPUT_PACKET, &packet_ret);
if (ret || !packet_ret) {
mpp_err("%p mpp meta get packet failed ret %d\n", ctx, ret);
goto DONE;
}
if (packet_ret != packet)
mpp_err_f("mismatch packet %p -> %p\n", packet, packet_ret);
}
if (data->frame_num > 0) {
if (data->frame_count >= data->frame_num)
data->loop_end = 1;
} else if (data->frame_num == 0) {
if (slot->eos)
data->loop_end = 1;
}
DONE:
mpp_packet_deinit(&packet);
return ret;
}
void *thread_decode(void *arg)
{
MpiDecLoopData *data = (MpiDecLoopData *)arg;
MpiDecTestCmd *cmd = data->cmd;
MppCtx ctx = data->ctx;
MppApi *mpi = data->mpi;
RK_S64 t_s, t_e;
memset(&data->checkcrc, 0, sizeof(data->checkcrc));
data->checkcrc.luma.sum = mpp_malloc(RK_ULONG, 512);
data->checkcrc.chroma.sum = mpp_malloc(RK_ULONG, 512);
t_s = mpp_time();
if (cmd->simple) {
while (!data->loop_end)
dec_simple(data);
} else {
/* NOTE: change output format before jpeg decoding */
if (MPP_FRAME_FMT_IS_YUV(cmd->format) || MPP_FRAME_FMT_IS_RGB(cmd->format)) {
MPP_RET ret = mpi->control(ctx, MPP_DEC_SET_OUTPUT_FORMAT, &cmd->format);
if (ret) {
mpp_err("Failed to set output format 0x%x\n", cmd->format);
return NULL;
}
}
while (!data->loop_end)
dec_advanced(data);
}
t_e = mpp_time();
data->elapsed_time = t_e - t_s;
data->frame_rate = (float)data->frame_count * 1000000 / data->elapsed_time;
data->delay = data->first_frm - data->first_pkt;
mpp_log("decode %d frames time %lld ms delay %3d ms fps %3.2f\n",
data->frame_count, (RK_S64)(data->elapsed_time / 1000),
(RK_S32)(data->delay / 1000), data->frame_rate);
MPP_FREE(data->checkcrc.luma.sum);
MPP_FREE(data->checkcrc.chroma.sum);
return NULL;
}
int dec_decode(MpiDecTestCmd *cmd)
{
// base flow context
MppCtx ctx = NULL;
MppApi *mpi = NULL;
// input / output
MppPacket packet = NULL;
MppFrame frame = NULL;
// paramter for resource malloc
RK_U32 width = cmd->width;
RK_U32 height = cmd->height;
MppCodingType type = cmd->type;
// config for runtime mode
MppDecCfg cfg = NULL;
RK_U32 need_split = 1;
// resources
MppBuffer frm_buf = NULL;
pthread_t thd;
pthread_attr_t attr;
MpiDecLoopData data;
MPP_RET ret = MPP_OK;
mpp_log("mpi_dec_test start\n");
memset(&data, 0, sizeof(data));
pthread_attr_init(&attr);
cmd->simple = (cmd->type != MPP_VIDEO_CodingMJPEG) ? (1) : (0);
if (cmd->have_output) {
data.fp_output = fopen(cmd->file_output, "w+b");
if (NULL == data.fp_output) {
mpp_err("failed to open output file %s\n", cmd->file_output);
goto MPP_TEST_OUT;
}
}
if (cmd->file_slt) {
data.fp_verify = fopen(cmd->file_slt, "wt");
if (!data.fp_verify)
mpp_err("failed to open verify file %s\n", cmd->file_slt);
}
ret = dec_buf_mgr_init(&data.buf_mgr);
if (ret) {
mpp_err("dec_buf_mgr_init failed\n");
goto MPP_TEST_OUT;
}
if (cmd->simple) {
ret = mpp_packet_init(&packet, NULL, 0);
if (ret) {
mpp_err("mpp_packet_init failed\n");
goto MPP_TEST_OUT;
}
} else {
RK_U32 hor_stride = MPP_ALIGN(width, 16);
RK_U32 ver_stride = MPP_ALIGN(height, 16);
ret = mpp_frame_init(&frame); /* output frame */
if (ret) {
mpp_err("mpp_frame_init failed\n");
goto MPP_TEST_OUT;
}
data.frm_grp = dec_buf_mgr_setup(data.buf_mgr, hor_stride * ver_stride * 4, 4, cmd->buf_mode);
if (!data.frm_grp) {
mpp_err("failed to get buffer group for input frame ret %d\n", ret);
ret = MPP_NOK;
goto MPP_TEST_OUT;
}
/*
* NOTE: For jpeg could have YUV420 and YUV422 the buffer should be
* larger for output. And the buffer dimension should align to 16.
* YUV420 buffer is 3/2 times of w*h.
* YUV422 buffer is 2 times of w*h.
* So create larger buffer with 2 times w*h.
*/
ret = mpp_buffer_get(data.frm_grp, &frm_buf, hor_stride * ver_stride * 4);
if (ret) {
mpp_err("failed to get buffer for input frame ret %d\n", ret);
goto MPP_TEST_OUT;
}
mpp_frame_set_buffer(frame, frm_buf);
}
// decoder demo
ret = mpp_create(&ctx, &mpi);
if (ret) {
mpp_err("mpp_create failed\n");
goto MPP_TEST_OUT;
}
mpp_log("%p mpi_dec_test decoder test start w %d h %d type %d\n",
ctx, width, height, type);
ret = mpp_init(ctx, MPP_CTX_DEC, type);
if (ret) {
mpp_err("%p mpp_init failed\n", ctx);
goto MPP_TEST_OUT;
}
mpp_dec_cfg_init(&cfg);
/* get default config from decoder context */
ret = mpi->control(ctx, MPP_DEC_GET_CFG, cfg);
if (ret) {
mpp_err("%p failed to get decoder cfg ret %d\n", ctx, ret);
goto MPP_TEST_OUT;
}
/*
* split_parse is to enable mpp internal frame spliter when the input
* packet is not aplited into frames.
*/
ret = mpp_dec_cfg_set_u32(cfg, "base:split_parse", need_split);
if (ret) {
mpp_err("%p failed to set split_parse ret %d\n", ctx, ret);
goto MPP_TEST_OUT;
}
ret = mpi->control(ctx, MPP_DEC_SET_CFG, cfg);
if (ret) {
mpp_err("%p failed to set cfg %p ret %d\n", ctx, cfg, ret);
goto MPP_TEST_OUT;
}
data.cmd = cmd;
data.ctx = ctx;
data.mpi = mpi;
data.loop_end = 0;
data.packet = packet;
data.frame = frame;
data.frame_count = 0;
data.frame_num = cmd->frame_num;
data.quiet = cmd->quiet;
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
ret = pthread_create(&thd, &attr, thread_decode, &data);
if (ret) {
mpp_err("failed to create thread for input ret %d\n", ret);
goto MPP_TEST_OUT;
}
if (cmd->frame_num < 0) {
// wait for input then quit decoding
mpp_log("*******************************************\n");
mpp_log("**** Press Enter to stop loop decoding ****\n");
mpp_log("*******************************************\n");
getc(stdin);
data.loop_end = 1;
}
pthread_join(thd, NULL);
cmd->max_usage = data.max_usage;
ret = mpi->reset(ctx);
if (ret) {
mpp_err("%p mpi->reset failed\n", ctx);
goto MPP_TEST_OUT;
}
MPP_TEST_OUT:
if (data.packet) {
mpp_packet_deinit(&data.packet);
data.packet = NULL;
}
if (frame) {
mpp_frame_deinit(&frame);
frame = NULL;
}
if (ctx) {
mpp_destroy(ctx);
ctx = NULL;
}
if (!cmd->simple) {
if (frm_buf) {
mpp_buffer_put(frm_buf);
frm_buf = NULL;
}
}
data.frm_grp = NULL;
if (data.buf_mgr) {
dec_buf_mgr_deinit(data.buf_mgr);
data.buf_mgr = NULL;
}
if (data.fp_output) {
fclose(data.fp_output);
data.fp_output = NULL;
}
if (data.fp_verify) {
fclose(data.fp_verify);
data.fp_verify = NULL;
}
if (cfg) {
mpp_dec_cfg_deinit(cfg);
cfg = NULL;
}
pthread_attr_destroy(&attr);
return ret;
}
int main(int argc, char **argv)
{
RK_S32 ret = 0;
MpiDecTestCmd cmd_ctx;
MpiDecTestCmd* cmd = &cmd_ctx;
memset((void*)cmd, 0, sizeof(*cmd));
cmd->format = MPP_FMT_BUTT;
cmd->pkt_size = MPI_DEC_STREAM_SIZE;
// parse the cmd option
ret = mpi_dec_test_cmd_init(cmd, argc, argv);
if (ret)
goto RET;
mpi_dec_test_cmd_options(cmd);
ret = dec_decode(cmd);
if (MPP_OK == ret)
mpp_log("test success max memory %.2f MB\n", cmd->max_usage / (float)(1 << 20));
else
mpp_err("test failed ret %d\n", ret);
RET:
mpi_dec_test_cmd_deinit(cmd);
return ret;
}
gcc mpp_dec_test.c -o mpp_dec_test `pkg-config --cflags --libs rockchip_mpp rockchip_vpu` -lutils
tail -f /var/log/syslog //开启新终端,监控输出
./mpp_dec_test -i /media/200frames_count.h264 -t 7 -n 200 -o ./decode.raw -w 640 -h 480
使用如下步骤安装Qt
sudo apt-get install build-essential
sudo apt-get install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools
sudo apt-get install qtcreator
sudo apt-get install qt5*
首先创建Qt项目,使用qmake,创建完后打开.pro文件加入下图所示opencv库的路径
INCLUDEPATH += /ur/local/include/ \
/usr/local/include/opencv/ \
/usr/local/innclude/opencv2
LIBS += /usr/local/lib/