本人【Luckfox幸狐 RV1106 Linux 开发板测评】帖子链接:
一、开箱及测试
二、SDK获取与编译镜像
三、GPIO点灯
四、通过PC机共享网络接入Internet和Ubuntu下Python点灯
五、编译Buildroot系统并测试摄像头
六、PWM控制——命令和C方式
七、PWM控制——Python和设备树方式
本篇继续测试Luckfox Pro Max板子的外围接口:ADC和UART——只测试了UART3。前面已经依照文档测评了GPIO和PWM输出,证明文档没有什么坑,所以本篇直接将ADC和UART3的控制合并到一起,编写一个“UART3接收命令,然后根据命令开启一次ADC转换”的实验程序。
图8-1 UART3连接和ADC管脚
板子串口启用UART3,19脚Tx,20脚Rx,有两个ADC(0/1)为31,32脚。串口通过USB-TTL连接到PC机,串口调试工具使用XCOM。
开发板的/sys/bus/iio/devices/iio\:device0/目录下是ADC设备的属性文件,主要操作三个:in_voltage_scale用于获取ADC读数和实际电压的转换因子,in_voltage0_raw用于获取ADC通道0读数,in_voltage1_raw用于获取ADC通道1读数。
开发板的/dev目录下包含UART相关的设备文件,UART3对应文件/dev/ttyS3。
1、Python方式
Python控制程序中,ADC没有使用库,直接进行文件操作,UART使用了serial库,需要注意的串口的读写函数对应参数都是bytes类型,尤其是调用serial.write()进行串口输出时,输出内容是字符串需要通过encode()函数转为bytes。具体代码如下:
- import serial
- import time
-
-
- uart3 = serial.Serial(
- "/dev/ttyS3",
- baudrate=115200,
- bytesize=serial.EIGHTBITS,
- stopbits=serial.STOPBITS_ONE,
- parity=serial.PARITY_NONE,
- timeout=1,
- )
-
-
- ADC_DIR = "/sys/bus/iio/devices/iio:device0"
-
-
- def read_value(file_path):
- with open(file_path, "r") as file:
- return file.read().strip()
-
-
- def main():
- print("Press Ctrl+C to quit")
- while True:
- buf = uart3.read(128)
- if b"ADC0" in buf:
-
- scale_value = float(read_value(f"{ADC_DIR}/in_voltage_scale"))
- IN0_raw_value = float(read_value(f"{ADC_DIR}/in_voltage0_raw"))
-
- IN0_voltage = f"{IN0_raw_value * scale_value / 1000:.2f}"
- print(f"IN0_Voltage: {IN0_voltage} V")
- uart3.write(f"IN0_Voltage: {IN0_voltage} V\n".encode('utf-8'))
- elif b"ADC1" in buf:
-
- scale_value = float(read_value(f"{ADC_DIR}/in_voltage_scale"))
- IN1_raw_value = float(read_value(f"{ADC_DIR}/in_voltage1_raw"))
- IN1_voltage = f"{IN1_raw_value * scale_value / 1000:.2f}"
- print(f"IN1_Voltage: {IN1_voltage} V")
- uart3.write(f"IN1_Voltage: {IN1_voltage} V\n".encode('utf-8'))
- time.sleep(2)
-
- if __name__ == "__main__":
- try:
- main()
- except KeyboardInterrupt:
- uart3.close()
- pass
图8-2 adc.py执行效果
程序执行效果如上图所示,XCOM连接板子UART3,发送“ADC0”过去则控制开发板对通道0进行一次ADC读值,发送“ADC1”则控制通道1。这里为了省事,两个ADC管脚都是悬空的,看输出应该是悬空为“高”——看文档ADC管脚参考电压就是1.8V。
2、C方式
C语音程序也是以操作设备文件的方式进行ADC和UART控制,其中需要用到struct termios结构体,这个结构体是在 POSIX 规范中定义的一个标准接口,它类似于系统 V 中的 termio 接口。这个结构体用于控制非同步通信端口,提供了一个常规的终端接口。通过设置 termios 类型的数据结构中的值和使用一组函数调用,你可以对终端接口进行控制。而在 Linux 系统中,struct termios 结构体常用于串口编程,用于设置串口参数、读取和写入串口数据等操作。通过调整这个结构体的各个成员,你可以控制串口的各种属性,如波特率、数据位、停止位、校验位等,以及终端的输入输出行为。相关代码如下:
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <string.h>
- #include <termios.h>
-
-
- int writeBuf(int fd, char *buffer, int size) {
- ssize_t bytes_written = write(fd, buffer, size);
- if (bytes_written < 0) {
- perror("Error writing to serial port");
- close(fd);
- return 1;
- }
- return 0;
- }
-
- int main() {
- printf("Press Ctrl+C to quit\n");
-
- const char *adc_dir = "/sys/bus/iio/devices/iio:device0";
-
- char in_voltage0_raw_path[256];
- char in_voltage1_raw_path[256];
- char in_voltage_scale_path[256];
-
- sprintf(in_voltage0_raw_path, "%s/in_voltage0_raw", adc_dir);
- sprintf(in_voltage1_raw_path, "%s/in_voltage1_raw", adc_dir);
- sprintf(in_voltage_scale_path, "%s/in_voltage_scale", adc_dir);
-
- FILE *scale_file = fopen(in_voltage_scale_path, "r");
- FILE *in0_raw_file = fopen(in_voltage0_raw_path, "r");
- FILE *in1_raw_file = fopen(in_voltage1_raw_path, "r");
-
- char serial_port[] = "/dev/ttyS3";
-
- int serial_fd;
-
- serial_fd = open(serial_port, O_RDWR | O_NOCTTY);
- if (serial_fd == -1) {
- perror("Failed to open serial port");
- return 1;
- }
-
- struct termios tty;
- memset(&tty, 0, sizeof(tty));
-
- if (tcgetattr(serial_fd, &tty) != 0) {
- perror("Error from tcgetattr");
- return 1;
- }
-
- cfsetospeed(&tty, B115200);
- cfsetispeed(&tty, B115200);
-
- tty.c_cflag &= ~PARENB;
- tty.c_cflag &= ~CSTOPB;
- tty.c_cflag &= ~CSIZE;
- tty.c_cflag |= CS8;
-
- if (tcsetattr(serial_fd, TCSANOW, &tty) != 0) {
- perror("Error from tcsetattr");
- return 1;
- }
-
- char rx_buffer[64];
- char tx_buffer[64];
- char buffer[32];
- float scale = 1.7578125;
- while (1) {
- int bytes_read = read(serial_fd, rx_buffer, sizeof(rx_buffer));
-
- if (bytes_read > 0) {
- rx_buffer[bytes_read] = '\0';
-
- fseek(scale_file, 0, SEEK_SET);
- if (scale_file) {
- fgets(buffer, sizeof(buffer), scale_file);
- scale = strtof(buffer, NULL);
- }
- if (strstr(rx_buffer, "ADC0") != NULL) {
-
- fseek(in0_raw_file, 0, SEEK_SET);
- if (in0_raw_file) {
- fgets(buffer, sizeof(buffer), in0_raw_file);
- int in0_raw_value = atoi(buffer);
- float in0_voltage = (in0_raw_value * scale) / 1000.0;
- printf("in ADC0 value: %d, volt: %.6f\n", in0_raw_value, in0_voltage);
- memset(tx_buffer, 0, 64);
- sprintf(tx_buffer, "IN0 Voltage: %.6f V\n", in0_voltage);
- if (writeBuf(serial_fd, tx_buffer, strlen(tx_buffer)) != 0) return 1;
- }
- } else if (strstr(rx_buffer, "ADC1") != NULL) {
-
- fseek(in1_raw_file, 0, SEEK_SET);
- if (in1_raw_file) {
- fgets(buffer, sizeof(buffer), in1_raw_file);
- int in1_raw_value = atoi(buffer);
- float in1_voltage = (in1_raw_value * scale) / 1000.0;
- printf("in ADC1 value: %d, volt:%.6f\n", in1_raw_value, in1_voltage);
- memset(tx_buffer, 0, 64);
- sprintf(tx_buffer, "IN1 Voltage: %.6f V\n", in1_voltage);
- if (writeBuf(serial_fd, tx_buffer, strlen(tx_buffer)) != 0) return 1;
- }
- }
- } else {
- printf("No data received.\n");
- }
-
- sleep(1);
- }
-
- fclose(scale_file);
- fclose(in0_raw_file);
- fclose(in1_raw_file);
- close(serial_fd);
- return 0;
- }