40PIN 扩展接口测试

GPIO 测试

选取一个 40pinGPIO 引脚来测试 GPIO 功能,例如选取 40pinpin3 引脚进行测试,pin3 对应的 gpio_num36。各引脚对应的 gpio_num 信息可以从《QuecPi-Pinmap-v1.0.pdf》文档中查找。

连接示意图,其中红色线接万用表正极,白色线接万用表负极:

使用 SHELL 命令控制

系统已默认启用 lgpiod 服务,依次执行如下命令来测试 40pinpin3 引脚的 gpio功能:

  • rgs c 999 go 4 #使用 go 命令打开文件 /dev/gpiochip4
  • rgs c 999 gso 0 36 #使用 gso 命令设置 gpio 36 为输出模式,这条命令里的 0 是上一条命令的返回内容,根据实际情况修改
  • rgs c 999 gw 0 36 0 #设置 gpio 36 为低电平,这个时候测试引脚电压值为 0V
  • rgs 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 测试

40PINpin3pin5 默认是 I2Cdataclock 引脚,测试 I2C 接口需要外接一个 I2C 设备,这里选择微雪环境传感器扩展板,通过 40pin 接口进行连接。

连接示意图:

图片1

微雪环境传感器扩展板

图片2

QuecPi 40PIN引脚

图片3

插上环境传感器扩展板的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 测试

40PINpin12、pin38pin40 可以配置为 spiSPI_CS、SPI_MISOSPI_MOSI 功能,再选择 pin3 作为 dc 引脚、pin5 作为 rst 引脚,这里选择微雪的 2.23OLED 扩展板。

连接示意图:

测试步骤:

  • 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测试

40PINpin8pin10 默认配置为 uart 功能,将电脑的 USB 转串口的 rxpin8txpin10


连接示意图: ![](images/quecpi-40pin-uart-pin8-10.jpg)

使用 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 PINpin33 默认配置为 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 值来调整风扇转速。