使用Python和pyserial库实现串口数据的发送和接收,与单片机通讯修改PID参数。

最近在使用并级PID控制倒立摆,使用板子上的按键调整PID参数。按钮按久了真的不舒服,想用无线串口与Python通讯实现键盘调参。以下是我研究了一晚上的成果,期间也踩了很多坑,写下来让大家少走点弯路。

1. 实现工具

软件:Python3.9.5
库: pyserial msvcrt time

2.库安装

注意要安装pyserial,不要安装成serial。
如果已经有serial库需要卸载掉。
打开控制台,输入以下代码

pip install pyserial

msvcrt 和 time 库是Python自带的,不需要手动安装

3. 避坑指南

1.msvcrt.getch() 该函数将键盘输入的单个字符转化为字节型返回。
所以进行判断时,要将字符转化为字节 b’ ’

if(mesg == b'q'):

2.串口只能以字节的形式通讯,所以只能接受和发送字节型数据(或字节串)

data = com.read()                        #接收字节型数据
print(data.decode('Ascii'),end='')       #以字符型解码输出

com.write(b'q')                          #发送字节型数据

3.msvcrt.getch() 该函数只能在控制台运行,否则该函数只会返回 b’\xff’
在这里插入图片描述
在这里插入图片描述

4.Python程序

import serial
import msvcrt
import time

#对键盘输入的字符进行判断,并使用串口发送出去
def send_mesg():
    if(mesg == b'q'):
        com.write(b'q')
    elif(mesg == b'e'):
        com.write(b'e')    
    elif(mesg == b'a'):
        com.write(b'a')  
    elif(mesg == b'd'):
        com.write(b'd')
    elif(mesg == b'w'):
        com.write(b'w')  
    elif(mesg == b's'):
        com.write(b's')
    elif(mesg == b' '):
        com.write(b' ')

#接收串口收到的数据,并打印出来
def recv_data():                                   #com.in_waiting 如果接收缓冲区有数据返回1
    if(com.in_waiting > 0):                        #这个判断是为了在每一次输出玩所有信息后进行一次换行
        while(com.in_waiting > 0):                 
            data = com.read()                      #该函数只能一次接受一个字节的信息,该循环持续到读取完所有信息
            print(data.decode('Ascii'),end='')     #将接受到的数据解码后打印出来
        print()

#首先进行串口参数配置 分别是 端口 波特率 字节大小 读取超时限制 停止位
com = serial.Serial(port="COM9", baudrate=115200,
                    bytesize=8, timeout=1, stopbits=serial.STOPBITS_ONE)

#死循环,进行串口通讯
while(1):
    mesg = msvcrt.getch()        #获取键盘输入的单个字符
    send_mesg()                  
    time.sleep(0.1)              #延时0.1秒,等待单片机接受信息并返回数据
    recv_data()

5.单片机程序

void uart_ctrl()
{
    if(uart_query(UART_2, &uart_buff))
    {
        switch(uart_buff)
        {
            case 'q': state_var--; break;
            case 'e': state_var++; break;
            case 'a': state_scale--; break;
            case 'd': state_scale++; break;
            case 's': flag_j=1; break;
            case 'w': flag_k=1; break;
            case ' ':
                {
                    flag_balance = !flag_balance;
                    if(flag_balance==1) printf("open balance\n");
                    else printf("close balance\n");
                    break;
                }
        }
        if(state_var == 6) state_var=1;
        if(state_scale == 6) state_scale=1;
        if(state_var == 0) state_var=5;
        if(state_scale == 0) state_scale=5;
        set_debug_var();
        if(uart_buff=='q'||uart_buff=='e'||uart_buff=='w'||uart_buff=='s')
        {
            switch(state_var)
            {
                case 1: printf("balance_kp:   %.2f\n",balance_kp); break;
                case 2: printf("balance_kd:   %.2f\n",balance_kd); break;
                case 3: printf("velocity_kp:  %.2f\n",velocity_kp); break;
                case 4: printf("velocity_ki:  %.2f\n",velocity_ki); break;
                case 5: printf("target_angle: %.2f\n",target_angle); break;
            }
        }
        if(uart_buff=='a'||uart_buff=='d')
        {
            switch(state_scale)
            {
                case 1: printf("0.01\n"); break;
                case 2: printf("0.1 \n"); break;
                case 3: printf("1   \n"); break;
                case 4: printf("10  \n"); break;
                case 5: printf("100 \n"); break;
            }
        }
    }
}

void set_debug_var()
{
    static float Scale;

    switch(state_scale)
    {
        case 1: Scale = 0.01; ips200_showstr(130, 1, "0.01"); break;
         case 2: Scale = 0.1; ips200_showstr(130, 1, "0.1 "); break;
           case 3: Scale = 1; ips200_showstr(130, 1, "1   "); break;
          case 4: Scale = 10; ips200_showstr(130, 1, "10  "); break;
         case 5: Scale = 100; ips200_showstr(130, 1, "100 "); break;
    }
    switch(state_var)
    {
          case 1: change_debug_var(&balance_kp, Scale); ips200_showstr(120,0,"bal_kp"); ips200_showfloat(120,2,balance_kp,4,2); break;
          case 2: change_debug_var(&balance_kd, Scale); ips200_showstr(120,0,"bal_kd"); ips200_showfloat(120,3,balance_kd,3,2); break;
         case 3: change_debug_var(&velocity_kp, Scale); ips200_showstr(120,0,"vel_kp"); ips200_showfloat(120,4,velocity_kp,4,2); break;
         case 4: change_debug_var(&velocity_ki, Scale); ips200_showstr(120,0,"vel_ki"); ips200_showfloat(120,5,velocity_ki,3,2); break;
        case 5: change_debug_var(&target_angle, Scale); ips200_showstr(120,0,"tar_ag "); ips200_showfloat(120,6,target_angle,2,2); break;
    }
}

void change_debug_var(float *var, float scale)
{
    if(flag_sw2 || flag_k==1) *var += scale, flag_k=0;
    if(flag_sw1 || flag_j==1) *var -= scale, flag_j=0;
}

6.效果展示

在这里插入图片描述

  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用 PySerial 和 PyQt5 实现串口实时状态发现并选择的过程中,我们可以使用 QComboBox 组件来实现串口的选择,使用 PySerial 来进行串口的实时状态发现。 首先,我们需要安装 PySerial ,可以使用以下命令进行安装: ``` pip install pyserial ``` 接着,我们需要在 PyQt5 界面中添加一个 QComboBox 组件,用于显示可用的串口。代码如下: ```python from PyQt5.QtWidgets import QComboBox # 创建一个 QComboBox 对象 self.combo_box = QComboBox(self) # 将 QComboBox 添加到界面上 self.layout.addWidget(self.combo_box) ``` 接着,我们需要使用 PySerial 实现串口的实时状态发现。代码如下: ```python import serial.tools.list_ports # 获取可用的串口列表 ports = serial.tools.list_ports.comports() # 遍历可用的串口列表,将串口添加到 QComboBox 中 for port in ports: self.combo_box.addItem(port.device) ``` 以上代码会获取所有可用的串口,并将它们添加到 QComboBox 中。 最后,我们需要在 QComboBox 中选择串口,以便进行通信。代码如下: ```python import serial # 获取选中的串口 port_name = self.combo_box.currentText() # 创建串口对象 ser = serial.Serial(port_name, 9600) ``` 以上代码会获取当前选中的串口名称,并创建一个串口对象以进行通信。 综上所述,我们可以使用 PyQt5 和 PySerial 实现串口实时状态发现并选择。完整的代码示例如下: ```python from PyQt5.QtWidgets import QComboBox, QWidget, QVBoxLayout import serial.tools.list_ports import serial class SerialMonitor(QWidget): def __init__(self): super().__init__() # 创建一个垂直布局 self.layout = QVBoxLayout(self) # 创建一个 QComboBox 对象 self.combo_box = QComboBox(self) # 将 QComboBox 添加到界面上 self.layout.addWidget(self.combo_box) # 获取可用的串口列表 ports = serial.tools.list_ports.comports() # 遍历可用的串口列表,将串口添加到 QComboBox 中 for port in ports: self.combo_box.addItem(port.device) # 为 QComboBox 组件添加回调函数 self.combo_box.currentIndexChanged.connect(self.on_serial_port_selected) def on_serial_port_selected(self): # 获取选中的串口 port_name = self.combo_box.currentText() # 创建串口对象 ser = serial.Serial(port_name, 9600) # 在此处进行串口通信 ``` 在以上代码中,我们创建了一个名为 SerialMonitor 的 QWidget 子类,它包含一个 QComboBox 和一个垂直布局。我们使用 PySerial 获取可用的串口列表,并将串口名称添加到 QComboBox 中。在选择串口时,我们使用 PySerial 创建一个串口对象以进行通信。你可以在 on_serial_port_selected 函数中添加任何你需要的串口通信代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值