40PIN 扩展接口测试
GPIO 测试
选取一个 40pin 的 GPIO 引脚来测试 GPIO 功能,例如选取 40pin 的 pin3 引脚进行测试,pin3 对应的 gpio_num 为 36。各引脚对应的 gpio_num 信息可以从《QuecPi-Pinmap-v1.0.pdf》文档中查找。
连接示意图,其中红色线接万用表正极,白色线接万用表负极:
使用 SHELL 命令控制
系统已默认启用 lgpiod 服务,依次执行如下命令来测试 40pin 的 pin3 引脚的 gpio功能:
rgs c 999 go 4
#使用 go 命令打开文件 /dev/gpiochip4rgs c 999 gso 0 36
#使用 gso 命令设置 gpio 36 为输出模式,这条命令里的 0 是上一条命令的返回内容,根据实际情况修改rgs c 999 gw 0 36 0
#设置 gpio 36 为低电平,这个时候测试引脚电压值为 0Vrgs c 999 gw 0 36 1
#设置 gpio 36 为高电平,这个时候测试引脚电压值为 3.3V
使用 C 代码控制
新建 gpio.c 文件,内容如下:
#include <stdlib.h> #include <lgpio.h> int main(int argc, char **argv) { int gpio_num = atoi(argv[1]); int pin_level = atoi(argv[2]); int handle = lgGpiochipOpen(4); lgGpioClaimOutput(handle, 0, gpio_num, 0); lgGpioWrite(handle, gpio_num, pin_level); }
编译:gcc -o gpio gpio.c -llgpio
执行:./gpio 36 0 #设置 gpio 36 为低电平,这个时候测试引脚电压值为 0V
执行:./gpio 36 1 #设置 gpio 36 为高电平,这个时候测试引脚电压值为 3.3V
I2C 测试
40PIN 的 pin3 和 pin5 默认是 I2C 的 data 和 clock 引脚,测试 I2C 接口需要外接一个 I2C 设备,这里选择微雪环境传感器扩展板,通过 40pin 接口进行连接。
连接示意图:

微雪环境传感器扩展板

QuecPi 40PIN引脚

插上环境传感器扩展板的QuecPi Alpha
使用 C 代码控制
测试步骤:
新建 envtest.c 文件,内容如下:
#include <stdio.h> #include <lgpio.h> #define I2C_DEV_NUM 9 #define BME280_ADDR 0x76 int32_t digT[3],digP[9],digH[6]; int32_t t_fine = 0.0; double compensate_P(int32_t adc_P) { double pressure = 0.0; double v1,v2; v1 = (t_fine / 2.0) - 64000.0; v2 = (((v1 / 4.0) * (v1 / 4.0)) / 2048) * digP[5]; v2 = v2 + ((v1 * digP[4]) * 2.0); v2 = (v2 / 4.0) + (digP[3] * 65536.0); v1 = (((digP[2] * (((v1 / 4.0) * (v1 / 4.0)) / 8192)) / 8) + ((digP[1] * v1) / 2.0)) / 262144; v1 = ((32768 + v1) * digP[0]) / 32768; if(v1 == 0) return 0; pressure = ((1048576 - adc_P) - (v2 / 4096)) * 3125; if (pressure < 0x80000000) pressure = (pressure * 2.0) / v1; else pressure = (pressure / v1) * 2; v1 = (digP[8] * (((pressure / 8.0) * (pressure / 8.0)) / 8192.0)) / 4096; v2 = ((pressure / 4.0) * digP[7]) / 8192.0; pressure = pressure + ((v1 + v2 + digP[6]) / 16.0) ; return (pressure/100); } double compensate_T(int32_t adc_T) { double temperature = 0.0; double v1,v2; v1 = (adc_T / 16384.0 - digT[0] / 1024.0) * digT[1]; v2 = (adc_T / 131072.0 - digT[0] / 8192.0) * (adc_T / 131072.0 - digT[0] / 8192.0) * digT[2]; t_fine = v1 + v2; temperature = t_fine / 5120.0; return temperature; } double compensate_H(int32_t adc_H) { double var_h = t_fine - 76800.0; if (var_h == 0) return 0; var_h = (adc_H - (digH[3] * 64.0 + digH[4]/16384.0 * var_h)) * (digH[1] / 65536.0 * (1.0 + digH[5] / 67108864.0 * var_h * (1.0 + digH[2] / 67108864.0 * var_h))); var_h = var_h * (1.0 - digH[0] * var_h / 524288.0); if (var_h > 100.0) var_h = 100.0; else if (var_h < 0.0) var_h = 0.0; return var_h; } void get_calib_param(int handle) { uint8_t calib[32]; for(int i=0;i<24;i++) { calib[i] = lgI2cReadByteData(handle, 0x88 + i); } calib[24] = lgI2cReadByteData(handle, 0xA1); for(int i=25,o=0;i<32;i++,o++) { calib[i] = lgI2cReadByteData(handle, 0xE1 + o); } digT[0] = (calib[1] << 8) | calib[0]; digT[1] = (calib[3] << 8) | calib[2]; digT[2] = (calib[5] << 8) | calib[4]; digP[0] = (calib[7] << 8) | calib[6]; digP[1] = (calib[9] << 8) | calib[8]; digP[2] = (calib[11] << 8) | calib[10]; digP[3] = (calib[13] << 8) | calib[12]; digP[4] = (calib[15] << 8) | calib[14]; digP[5] = (calib[17] << 8) | calib[16]; digP[6] = (calib[19] << 8) | calib[18]; digP[7] = (calib[21] << 8) | calib[20]; digP[8] = (calib[23] << 8) | calib[22]; digH[0] = calib[24]; digH[1] = (calib[26] << 8) | calib[25]; digH[2] = calib[27]; digH[3] = (calib[28] << 4) | (0x0f & calib[29]); digH[4] = (calib[30] << 4) | ((calib[29] >> 4) & 0x0f); digH[5] = calib[31]; for(int i=1;i<2;i++) if((digT[i] & 0x8000) != 0) digT[i] = (-digT[i] ^ 0xFFFF) + 1; for(int i=1;i<8;i++) if ((digP[i] & 0x8000) != 0) digP[i]=(-digP[i] ^ 0xFFFF) + 1 ; for(int i=0;i<6;i++) if ((digH[i] & 0x8000) != 0) digH[i] = (-digH[i] ^ 0xFFFF) + 1; } int main(int argc, char **argv) { uint8_t data[8]; double value[3]; int handle = lgI2cOpen(I2C_DEV_NUM, BME280_ADDR, 0); lgI2cWriteByteData(handle, 0xF2, 0x01); lgI2cWriteByteData(handle, 0xF4, 0x27); lgI2cWriteByteData(handle, 0xF5, 0xA0); get_calib_param(handle); for(int i=0;i<8;i++) { data[i] = lgI2cReadByteData(handle, 0xF7 + i); } value[0] = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4); value[1] = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4); value[2] = (data[6] << 8) | data[7]; value[0] = compensate_P(value[0]); value[1] = compensate_T(value[1]); value[2] = compensate_H(value[2]); printf("pressure: %7.2f hPa\n", value[0]); printf("temperature: %7.2f C\n" , value[1]); printf("humidity: %7.2f %\n" , value[2]); lgI2cClose(handle); }
编译:gcc -o envtest envtest.c -llgpio
运行:./envtest #输出内容包含采集的气压、温度和湿度信息
SPI 测试
40PIN 的 pin12、pin38 和 pin40 可以配置为 spi 的 SPI_CS、SPI_MISO 和 SPI_MOSI 功能,再选择 pin3 作为 dc 引脚、pin5 作为 rst 引脚,这里选择微雪的 2.23 寸 OLED 扩展板。
连接示意图:
测试步骤:
wget http://www.waveshare.net/w/upload/c/c5/2.23inch-OLED-HAT-Code.7z #下载微雪提供的源码
7z x 2.23inch-OLED-HAT-Code.7z #解压源码
cd 2.23inch-OLED-HAT-Code/Without\ scrolling/Raspberry\ Pi/SPI/c #切换到源码目录
将 example 目录下的 main.c 内容替换为:
#include "test.h" int main(int argc, char *argv[]) { char value[10]={'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; time_t now; struct tm *timenow; char buffer[NUM_MAXBUF]; extern int GPIO_Handle; extern int SPI_Handle; GPIO_Handle = lgGpiochipOpen(4); if (GPIO_Handle < 0) { printf( "gpiochip4 Export Failed\n"); return -1; } lgGpioClaimOutput(GPIO_Handle, 0, 47 , LG_HIGH); lgGpioClaimOutput(GPIO_Handle, 0, OLED_RST, LG_LOW); lgGpioClaimOutput(GPIO_Handle, 0, OLED_DC , LG_LOW); printf("USE_SPI\r\n"); SPI_Handle = lgSpiOpen(14, 0, 10000000, 0); SSD1305_begin(); SSD1305_bitmap(7, 0, waveshare_ch,112,32); SSD1305_display(); DEV_Delay_ms(1000); SSD1305_clear(); SSD1305_bitmap(0, 8, waveshare_en,128,32); SSD1305_display(); DEV_Delay_ms(1000); SSD1305_clear(); while(1) { time(&now); timenow = localtime(&now); SSD1305_bitmap(0, 2, Signal816, 16, 8); SSD1305_bitmap(24, 2, Bluetooth88, 8, 8); SSD1305_bitmap(40, 2, Msg816, 16, 8); SSD1305_bitmap(64, 2, GPRS88, 8, 8); SSD1305_bitmap(90, 2, Alarm88, 8, 8); SSD1305_bitmap(112, 2, Bat816, 16, 8); SSD1305_string(0, 52, "MUSIC", 12, 0); SSD1305_string(52, 52, "MENU", 12, 0); SSD1305_string(98, 52, "PHONE", 12, 0); SSD1305_char1616(0, 16, value[timenow->tm_hour/10]); SSD1305_char1616(16, 16, value[timenow->tm_hour%10]); SSD1305_char1616(32, 16, ':'); SSD1305_char1616(48, 16, value[timenow->tm_min/10]); SSD1305_char1616(64, 16, value[timenow->tm_min%10]); SSD1305_char1616(80, 16, ':'); SSD1305_char1616(96, 16, value[timenow->tm_sec/10]); SSD1305_char1616(112, 16, value[timenow->tm_sec%10]); SSD1305_display(); } return 0; }
编译: make
运行: ./main
运行效果如下图:
UART测试
40PIN 的 pin8 和 pin10 默认配置为 uart 功能,将电脑的 USB 转串口的 rx 接 pin8、tx 接 pin10。
连接示意图: 
使用 C 代码控制
新建 uart.c 文件,内容如下:
#include <stdio.h> #include <string.h> #include <lgpio.h> int strip_head_and_tail(char *data, int data_len) { int found_tail = 0; if (data_len > 0 && data[0] == '\r') { bcopy(data + 1, data, data_len-1); data_len--; } if (data_len > 0 && data[0] == '\n') { bcopy(data + 1, data, data_len-1); data_len--; } if (data_len > 0 && data[data_len - 1] == '\r') { data_len--; data[data_len] = 0; found_tail = 1; } if (data_len > 0 && data[data_len - 1] == '\n') { data_len--; data[data_len] = 0; found_tail = 1; } return found_tail; } int main(int argc, char **argv) { int handle = lgSerialOpen("/dev/ttyHS2", 115200, 0); char data[512]; int data_len = 0; for (;;) { int read_len = lgSerialRead(handle, data + data_len, sizeof(data) - data_len); if (read_len > 0) { data_len += read_len; } if (strip_head_and_tail(data, data_len)) { printf("received: %s\n", data); lgSerialWrite(handle, "Received.\r\n", 11); } lguSleep(100); } lgSerialClose(handle); }
编译: gcc -o uart uart.c -llgpio
运行: ./uart #此时 USB 转串口转换器与 PC 连接,使用 putty 等支持串口通行的软件与该串口服务程序通行,putty 等客户端输入内容并以回车键结尾,服务端程序会打印用户输入的内容并返回“Received.”给客户端。
使用 Python 脚本控制
创建服务端程序 uart.py,文件内容如下:
import serial import threading PORT = '/dev/ttyHS2' BAUDRATE = 115200 TIMEOUT = 1 ser = serial.Serial(PORT, BAUDRATE, timeout=TIMEOUT) def read_and_echo(ser): while True: data = ser.readline() if data: print(f"Received: {data.decode().strip()}") ser.write(“Received.\r\n”) def main(): if ser.is_open: print(f"Serial port {PORT} is open. Echo service started.") thread = threading.Thread(target=read_and_echo, args=(ser,)) thread.daemon = True thread.start() try: while True: pass except KeyboardInterrupt: print("Exiting program.") else: print(f"Failed to open serial port {PORT}.") ser.close() print(f"Serial port {PORT} is closed.") if __name__ == "__main__": main()
运行: python test.py #此时 USB 转串口转换器与 PC 连接,使用 putty 等支持串口通行的软件与该串口服务程序通行,putty 等客户端输入内容并以回车键结尾,服务端程序会打印用户输入的内容并返回“Received.”给客户端。
PWM 测试
40 PIN 的 pin33 默认配置为 pwm 功能,这里选择微雪的 4pin PWM 协议的调速风扇做为测试设备。
连接示意图:
使用 C 代码控制
创建 pwm.c 文件,文件内容如下:
#include <stdio.h> #include <lgpio.h> int main(int argc, char **argv) { int h; int gpio = 78; float pwmFrequency = 1000; float pwmDutyCycle = 50; h = lgGpiochipOpen(4); if (h < 0) { printf("ERROR: %s (%d)\n", lguErrorText(h), h); return 1; } int e = lgGpioClaimOutput(h, 0, gpio, 0); if (e < 0) { printf("ERROR: %s (%d)\n", lguErrorText(e), e); return 1; } e = lgTxPwm(h, gpio, pwmFrequency, pwmDutyCycle, 0, 0); if (e < 0) { printf("ERROR: %s (%d)\n", lguErrorText(e), e); return 1; } lguSleep(5); lgGpioFree(h, gpio); lgGpiochipClose(h); return 0; }
编译: gcc pwm.c -o pwm -llgpio
执行:./pwm #风扇会以中等转速运转,可以调整代码中的 pwmDutyCycle 值来调整风扇转速。