嵌入式开发日记(6)——对串口数据读取的优化以及处理程序的改写

改进版代码的github地址如下,读取并记录到本地文件。https://github.com/hanjintao1996/jy61-/tree/master

如有帮助请在github点赞,感激不尽。

#define IOBEGIN 22 
#define IOEND 53               //定义初始化的IO口
// the setup function runs once when you press reset or power the board
void setup() {
    Serial.begin(9600);         //初始化端口
    Serial.print("Ready");
    for(int i=IOBEGIN;i<=IOEND;i++)
    {  
        
        pinMode(i,OUTPUT);
    } 
}
 
// the loop function runs over and over again forever
void loop() {
  if(Serial.available()){
   char ch = Serial.read();        //读取串口
   Serial.print(ch);
   switch(ch){                     //根据传入信息判断工作模式
   case'1':
   digitalWrite(22,HIGH);
   digitalWrite(23,HIGH);
   digitalWrite(24,HIGH);
   digitalWrite(25,HIGH);
   digitalWrite(26,HIGH);
   digitalWrite(27,HIGH);
   break;
   case'2':
   digitalWrite(22,LOW);
   digitalWrite(23,LOW);
   digitalWrite(24,LOW);
   digitalWrite(25,LOW);
   digitalWrite(26,LOW);
   digitalWrite(27,LOW);
   break;
}}}


因为之前用原始的方法进行数据的读取,导致在出现丢包之类的情况发生的时候会出现程序错误,在实验室师兄的帮助下,改写了之前的程序,具体情况参见注释:

import serial

ACCData=[0.0]*8
GYROData=[0.0]*8
AngleData=[0.0]*8         #定义三个数组,分别存储加速度角速度与角度的值

FrameState = 0            #通过0x后面的值判断属于哪一种情况
Bytenum = 0               #读取到这一段的第几位
CheckSum = 0              #求和校验位         

def DueData(inputdata):   #新增的核心程序,对读取的数据进行划分,各自读到对应的数组里
    global  FrameState    #在局部修改全局变量,要进行global的定义
    global  Bytenum
    global  CheckSum
    for data in inputdata:  #在输入的数据进行遍历
        if FrameState==0:   #当未确定状态的时候,进入以下判断
            if data==0x55 and Bytenum==0: #0x55位于第一位时候,开始读取数据,增大bytenum
                CheckSum=data
                Bytenum=1
                continue
            elif data==0x51 and Bytenum==1:#在byte不为0 且 识别到 0x51 的时候,改变frame
                CheckSum+=data
                FrameState=1
                Bytenum=2
            elif data==0x52 and Bytenum==1: #同理
                CheckSum+=data
                FrameState=2
                Bytenum=2
            elif data==0x53 and Bytenum==1:
                CheckSum+=data
                FrameState=3
                Bytenum=2
        elif FrameState==1: # acc    #已确定数据代表加速度
            if Bytenum<10:            # 读取8个数据
                ACCData[Bytenum-2]=data # 从0开始
                CheckSum+=data
                Bytenum+=1
            else:
                if data == (CheckSum&0xff):  #假如校验位正确
                    print(get_acc(ACCData))
                CheckSum=0                  #各数据归零,进行新的循环判断
                Bytenum=0
                FrameState=0
        elif FrameState==2: # gyro
            if Bytenum<10:
                GYROData[Bytenum-2]=data
                CheckSum+=data
                Bytenum+=1
            else:
                if data == (CheckSum&0xff):
                    print(get_gyro(GYROData))
                CheckSum=0
                Bytenum=0
                FrameState=0
        elif FrameState==3: # angle
            if Bytenum<10:
                AngleData[Bytenum-2]=data
                CheckSum+=data
                Bytenum+=1
            else:
                if data == (CheckSum&0xff):
                    print(get_angle(AngleData))
                CheckSum=0
                Bytenum=0
                FrameState=0


def get_acc(datahex):  #加速度
    axl = datahex[0]                                        
    axh = datahex[1]
    ayl = datahex[2]                                        
    ayh = datahex[3]
    azl = datahex[4]                                        
    azh = datahex[5]
    
    k_acc = 16

    acc_x = (axh << 8 | axl) / 32768 * k_acc
    acc_y = (ayh << 8 | ayl) / 32768 * k_acc
    acc_z = (azh << 8 | azl) / 32768 * k_acc
    if acc_x >= k_acc:
        acc_x -= 2 * k_acc
    if acc_y >= k_acc:
        acc_y -= 2 * k_acc
    if acc_z >= k_acc:
        acc_z-= 2 * k_acc
    
    return acc_x,acc_y,acc_z


def get_gyro(datahex):                                          #陀螺仪
    wxl = datahex[0]                                        
    wxh = datahex[1]
    wyl = datahex[2]                                        
    wyh = datahex[3]
    wzl = datahex[4]                                        
    wzh = datahex[5]
    k_gyro = 2000

    gyro_x = (wxh << 8 | wxl) / 32768 * k_gyro
    gyro_y = (wyh << 8 | wyl) / 32768 * k_gyro
    gyro_z = (wzh << 8 | wzl) / 32768 * k_gyro
    if gyro_x >= k_gyro:
        gyro_x -= 2 * k_gyro
    if gyro_y >= k_gyro:
        gyro_y -= 2 * k_gyro
    if gyro_z >=k_gyro:
        gyro_z-= 2 * k_gyro
    return gyro_x,gyro_y,gyro_z


def get_angle(datahex):                                 #角度
    rxl = datahex[0]                                        
    rxh = datahex[1]
    ryl = datahex[2]                                        
    ryh = datahex[3]
    rzl = datahex[4]                                        
    rzh = datahex[5]
    k_angle = 180

    angle_x = (rxh << 8 | rxl) / 32768 * k_angle
    angle_y = (ryh << 8 | ryl) / 32768 * k_angle
    angle_z = (rzh << 8 | rzl) / 32768 * k_angle
    if angle_x >= k_angle:
        angle_x -= 2 * k_angle
    if angle_y >= k_angle:
        angle_y -= 2 * k_angle
    if angle_z >=k_angle:
        angle_z-= 2 * k_angle

    return angle_x,angle_y,angle_z
 
 
if __name__=='__main__':  #主函数
    ser = serial.Serial("com8", 115200, timeout=0.5)  # 打开端口,改到循环外
    print(ser.is_open)
    while(1):
        #datahex = (ser.read(33).hex()) #之前转换成了字符串,一位变成了两位
        datahex = ser.read(33)       #不用hex()转化,直接用read读取的即是16进制
        DueData(datahex)            #调用程序进行处理

主要设计到数据读取的格式问题,进制问题,以及如何找到头数据,如何利用校验位。

另外,shift + tab可以往前缩进

#define IOBEGIN 22 
#define IOEND 53               //定义初始化的IO口
// the setup function runs once when you press reset or power the board
void setup() {
    Serial.begin(9600);         //初始化端口
    Serial.print("Ready");
    for(int i=IOBEGIN;i<=IOEND;i++)
    {  
        
        pinMode(i,OUTPUT);
    } 
}
 
// the loop function runs over and over again forever
void loop() {
  if(Serial.available()){
   char ch = Serial.read();        //读取串口
   Serial.print(ch);
   switch(ch){                     //根据传入信息判断工作模式
   case'1':
   digitalWrite(22,HIGH);
   digitalWrite(24,HIGH);
   break;
   case'2':
   digitalWrite(22,LOW);
   digitalWrite(24,LOW);
   break;
}}}
import serial
import time
import easygui

ACCData=[0.0]*8
GYROData=[0.0]*8
AngleData=[0.0]*8

FrameState = 0
Bytenum = 0
CheckSum = 0

shakedegree = 0

def DueData(inputdata):
    global  FrameState
    global  Bytenum
    global  CheckSum
    for data in inputdata:
        if FrameState==0:
            if data==0x55 and Bytenum==0:
                CheckSum=data
                Bytenum=1
                continue
            elif data==0x51 and Bytenum==1:
                CheckSum+=data
                FrameState=1
                Bytenum=2
            elif data==0x52 and Bytenum==1:
                CheckSum+=data
                FrameState=2
                Bytenum=2
            elif data==0x53 and Bytenum==1:
                CheckSum+=data
                FrameState=3
                Bytenum=2
        elif FrameState==1: # acc
            if Bytenum<10:
                ACCData[Bytenum-2]=data
                CheckSum+=data
                Bytenum+=1
            else:
                if data == (CheckSum&0xff):
                    #print(get_acc(ACCData))
                    accvalue = get_acc(ACCData)
                    return accvalue 
                CheckSum=0
                Bytenum=0
                FrameState=0
        elif FrameState==2: # gyro
            if Bytenum<10:
                GYROData[Bytenum-2]=data
                CheckSum+=data
                Bytenum+=1
            else:
                if data == (CheckSum&0xff):
                    pass
                    #print(get_gyro(GYROData))
                CheckSum=0
                Bytenum=0
                FrameState=0
        elif FrameState==3: # angle
            if Bytenum<10:
                AngleData[Bytenum-2]=data
                CheckSum+=data
                Bytenum+=1
            else:
                if data == (CheckSum&0xff):
                    pass#print(get_angle(AngleData))
                CheckSum=0
                Bytenum=0
                FrameState=0


def get_acc(datahex):  #加速度
    axl = datahex[0]                                        
    axh = datahex[1]
    ayl = datahex[2]                                        
    ayh = datahex[3]
    azl = datahex[4]                                        
    azh = datahex[5]
    
    k_acc = 16

    acc_x = (axh << 8 | axl) / 32768 * k_acc
    acc_y = (ayh << 8 | ayl) / 32768 * k_acc
    acc_z = (azh << 8 | azl) / 32768 * k_acc
    if acc_x >= k_acc:
        acc_x -= 2 * k_acc
    if acc_y >= k_acc:
        acc_y -= 2 * k_acc
    if acc_z >= k_acc:
        acc_z-= 2 * k_acc
    
    acc = [acc_x,acc_y,acc_z]
    return acc


def get_gyro(datahex):                                          #陀螺仪
    wxl = datahex[0]                                        
    wxh = datahex[1]
    wyl = datahex[2]                                        
    wyh = datahex[3]
    wzl = datahex[4]                                        
    wzh = datahex[5]
    k_gyro = 2000

    gyro_x = (wxh << 8 | wxl) / 32768 * k_gyro
    gyro_y = (wyh << 8 | wyl) / 32768 * k_gyro
    gyro_z = (wzh << 8 | wzl) / 32768 * k_gyro
    if gyro_x >= k_gyro:
        gyro_x -= 2 * k_gyro
    if gyro_y >= k_gyro:
        gyro_y -= 2 * k_gyro
    if gyro_z >=k_gyro:
        gyro_z-= 2 * k_gyro
    return gyro_x,gyro_y,gyro_z


def get_angle(datahex):                                 #角度
    rxl = datahex[0]                                        
    rxh = datahex[1]
    ryl = datahex[2]                                        
    ryh = datahex[3]
    rzl = datahex[4]                                        
    rzh = datahex[5]
    k_angle = 180

    angle_x = (rxh << 8 | rxl) / 32768 * k_angle
    angle_y = (ryh << 8 | ryl) / 32768 * k_angle
    angle_z = (rzh << 8 | rzl) / 32768 * k_angle
    if angle_x >= k_angle:
        angle_x -= 2 * k_angle
    if angle_y >= k_angle:
        angle_y -= 2 * k_angle
    if angle_z >=k_angle:
        angle_z-= 2 * k_angle

    return angle_x,angle_y,angle_z
 
def shakecharge(self):                #震颤判断函数
    ifshake = 0           #震颤次数
    ifshake_0 =0          #是否归零
    limit_a1 = 0.5
    limit_a2 = 0.8
    limit_a3 = 1.2        #震动分级
    interval_a = 5        #更新间隔
    acc_fre[0] = acc_fre[0] + 1 #重要!不能用变量,要用list
    global shakedegree
    shakedegree= shakedegree - 0.1    #十次平稳后切断
    print(acc_fre[0])
    if acc_fre[0] % interval_a == 0:  #采样
        acc_old[0] = acc[0]
        acc_old[1] = acc[1]
        acc_old[2] = acc[2]
    if acc_fre[0] % (interval_a * 10) == 0: #重置
        if ifshake == ifshake_0:           #如果没更新
            ifshake = ifshake_0 = 0
            print('——————重置!')
        else:                              #更新归零阈值
            ifshake_0 = ifshake
            print('******更新! ')
    else:
        pass
 
    if acc_fre[0] > interval_a*2 and (abs(acc[0] - acc_old[0]) > limit_a3 or acc[1] - acc_old[1] > limit_a3 or acc[2] - acc_old[2] > limit_a3) :
        print("===重度震颤!!!!!")   #LED灯亮
        shakedegree = 1
        #time.sleep(1)
        demo = b"1"
        ser1.write(demo)
        s = ser1.read(1)
        print(s)
    elif acc_fre[0] > interval_a*2 and (abs(acc[0] - acc_old[0]) > limit_a2 or acc[1] - acc_old[1] > limit_a2 or acc[2] - acc_old[2] > limit_a2):
        print("===中度震颤!!!!!")
        shakedegree = 1
        demo2 = b"1"
        ser1.write(demo2)
        #time.sleep(1)
        s = ser1.read(1)
        print(s)
        ifshake = 0
 
    elif acc_fre[0] > interval_a*2 and (abs(acc[0] - acc_old[0]) > limit_a1 or acc[1] - acc_old[1] > limit_a1 or acc[2] - acc_old[2] > limit_a1):
        print("===轻度震颤!!!!!")
        shakedegree = 1
        demo3 = b"1"
        ser1.write(demo3)
        #time.sleep(1)
        s = ser1.read(1)
        print(s)
        ifshake = 0
    else:
        shakedegree = shakedegree - 0.5
        print(shakedegree)
        if shakedegree < 0:
            demo4 = b"2"
            ser1.write(demo4)

if __name__=='__main__':
    ser1 = serial.Serial("com9", 9600)  # 打开Arduino端口
    #ser = serial.Serial("com8", 115200)  # 打开端口,改到循环外,避免一直开闭串口
    print(ser1.is_open)
    demo3 = b"1"
    ser1.write(demo3)
    acc_old = [0,0,0]
    acc_fre = [1]
    
    while(1):
        ser = serial.Serial("com8", 115200)  # 打开端口,放在循环内,可以避免连接不畅导致掉线
        datahex = ser.read(33)
        acc = DueData(datahex)
        if acc:
            print(acc)
            shakecharge(acc)
        #print(acc_fre)
        ser.close()
        time.sleep(0.2)

读取并记录到本地csv文件。

import pandas as pd
import numpy as np

#txt = np.loadtxt('2020-05-31.txt')
import serial
import os
import time
import csv
ACCData = [0.0] * 8
GYROData = [0.0] * 8
AngleData = [0.0] * 8  # 定义三个数组,分别存储加速度角速度与角度的值

FrameState = 0  # 通过0x后面的值判断属于哪一种情况
Bytenum = 0  # 读取到这一段的第几位
CheckSum = 0  # 求和校验位


def DueData(inputdata):  # 新增的核心程序,对读取的数据进行划分,各自读到对应的数组里
    global FrameState  # 在局部修改全局变量,要进行global的定义
    global Bytenum
    global CheckSum
    for data in inputdata:  # 在输入的数据进行遍历
        if FrameState == 0:  # 当未确定状态的时候,进入以下判断
            if data == 0x55 and Bytenum == 0:  # 0x55位于第一位时候,开始读取数据,增大bytenum
                CheckSum = data
                Bytenum = 1
                continue
            elif data == 0x51 and Bytenum == 1:  # 在byte不为0 且 识别到 0x51 的时候,改变frame
                CheckSum += data
                FrameState = 1
                Bytenum = 2
            elif data == 0x52 and Bytenum == 1:  # 同理
                CheckSum += data
                FrameState = 2
                Bytenum = 2
            elif data == 0x53 and Bytenum == 1:
                CheckSum += data
                FrameState = 3
                Bytenum = 2
        elif FrameState == 1:  # acc    #已确定数据代表加速度
            if Bytenum < 10:  # 读取8个数据
                ACCData[Bytenum - 2] = data  # 从0开始
                CheckSum += data
                Bytenum += 1
            else:
                if data == (CheckSum & 0xff):  # 假如校验位正确
                    print('加速度',get_acc(ACCData))
                    newacc = get_acc(ACCData)
                    file_write_obj.writelines(newacc)
                 #   file_write_obj.write('\n')
                CheckSum = 0  # 各数据归零,进行新的循环判断
                Bytenum = 0
                FrameState = 0
        elif FrameState == 2:  # gyro
            if Bytenum < 10:
                GYROData[Bytenum - 2] = data
                CheckSum += data
                Bytenum += 1
            else:
                if data == (CheckSum & 0xff):
                    print('角速度',get_gyro(GYROData))
                    newgyro = get_gyro(GYROData) #文件写入
                    file_write_obj.writelines(newgyro)
                   # file_write_obj.write('\n')
                CheckSum = 0
                Bytenum = 0
                FrameState = 0
        elif FrameState == 3:  # angle
            if Bytenum < 10:
                AngleData[Bytenum - 2] = data
                CheckSum += data
                Bytenum += 1
            else:
                if data == (CheckSum & 0xff):
                    print('角度',get_angle(AngleData))
                    newangle = get_angle(AngleData)
                    file_write_obj.writelines(newangle)
                    file_write_obj.write('\n')
                CheckSum = 0
                Bytenum = 0
                FrameState = 0


def get_acc(datahex):  # 加速度
    axl = datahex[0]
    axh = datahex[1]
    ayl = datahex[2]
    ayh = datahex[3]
    azl = datahex[4]
    azh = datahex[5]

    k_acc = 16

    acc_x = (axh << 8 | axl) / 32768 * k_acc
    acc_y = (ayh << 8 | ayl) / 32768 * k_acc
    acc_z = (azh << 8 | azl) / 32768 * k_acc
    if acc_x >= k_acc:
        acc_x -= 2 * k_acc
    if acc_y >= k_acc:
        acc_y -= 2 * k_acc
    if acc_z >= k_acc:
        acc_z -= 2 * k_acc

    return str(acc_x)+',', str(acc_y)+',', str(acc_z)+','


def get_gyro(datahex):  # 陀螺仪
    wxl = datahex[0]
    wxh = datahex[1]
    wyl = datahex[2]
    wyh = datahex[3]
    wzl = datahex[4]
    wzh = datahex[5]
    k_gyro = 2000

    gyro_x = (wxh << 8 | wxl) / 32768 * k_gyro
    gyro_y = (wyh << 8 | wyl) / 32768 * k_gyro
    gyro_z = (wzh << 8 | wzl) / 32768 * k_gyro
    if gyro_x >= k_gyro:
        gyro_x -= 2 * k_gyro
    if gyro_y >= k_gyro:
        gyro_y -= 2 * k_gyro
    if gyro_z >= k_gyro:
        gyro_z -= 2 * k_gyro
    return str(gyro_x)+',', str(gyro_y)+',', str(gyro_z)+','


def get_angle(datahex):  # 角度
    rxl = datahex[0]
    rxh = datahex[1]
    ryl = datahex[2]
    ryh = datahex[3]
    rzl = datahex[4]
    rzh = datahex[5]
    k_angle = 180

    angle_x = (rxh << 8 | rxl) / 32768 * k_angle
    angle_y = (ryh << 8 | ryl) / 32768 * k_angle
    angle_z = (rzh << 8 | rzl) / 32768 * k_angle
    if angle_x >= k_angle:
        angle_x -= 2 * k_angle
    if angle_y >= k_angle:
        angle_y -= 2 * k_angle
    if angle_z >= k_angle:
        angle_z -= 2 * k_angle

    return str(angle_x)+',', str(angle_y)+',', str(angle_z)+','


if __name__ == '__main__':  # 主函数
    ser = serial.Serial("com8", 115200, timeout=0.5)  # 打开端口,改到循环外
    print(ser.is_open)
    Time = time.strftime("%Y-%m-%d") #记录当前时间
    file_write_obj = open(Time+".txt", 'w') #建立记录文件
    file_write_obj.write('ax,ay,az,gx,gy,gz,anx,any,anz')
    file_write_obj.write('\n')
    while (1):
        # datahex = (ser.read(33).hex()) #之前转换成了字符串,一位变成了两位
        datahex = ser.read(33)  # 不用hex()转化,直接用read读取的即是16进制
        print(len(datahex))
        print('原始数据',datahex[0:15])
        print('        ', datahex[15:])
        DueData(datahex)  # 调用程序进行处理
        with open('csv数据2.csv', 'w+', newline='') as csvfile:
            spamwriter = csv.writer(csvfile, dialect='excel')
            # 读要转换的txt文件,文件每行各词间以字符分隔
            with open(Time+".txt", 'r', encoding='utf-8') as filein:
                for line in filein:
                    line_list = line.strip('\n').split(',')  # 我这里的数据之间是以 ; 间隔的
                    spamwriter.writerow(line_list)
    file_write_obj.close()

 

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值