數字系統實驗:倒車雷達

M3M4M5M6:(本人的本職負責爲M5M6,兼職負責M3M4)
一、個人模塊部分的不同方案分析:
M5M6所負責的是A級實驗的上位機軟件模塊,要求負責控制命令發送、採樣數據接收、數據處理、數據圖形化顯示、數據文件保存等等。相當於要我們寫一個功能完備的串口助手出來,並且相對於之前在第八次實驗老師給的串口助手更加高級,需要增添圖形顯示界面。我從開始到最終結束,從網上找到了十幾個大神所給的代碼文件,有Python的有VS的,後來發現完全沒法用,太高級,所以乾脆自己寫,又寫了四五個版本,最終得到一個能用的。可以比較完備的顯示的。
在這裏插入圖片描述
網上代碼
在這裏插入圖片描述
自己寫的
由於我們選用Python語言來設計上位機的軟件功能模塊和UI交互模塊,這裏通過學習從網上找來的代碼,發現可以使用Python中的serial庫來設計串口通信功能模塊,通過pyqt庫或者tkinter庫來設計UI交互界面,pygragh庫可以進行圖形繪製,這麼多的網上代碼無怪乎如此。所以我嘗試了很多。首先嚐試從serial庫入手,先嚐試建立起串口通信,這就是串口1文件夾,發現實際上串口通信在上位機很簡單,只需要調用read和write函數就可以;於是就開始設計圖像繪製,這就是串口2文件夾,發現可以使用pygragh庫進行圖形的實時繪製;然後開始設計UI交互界面,這裏很麻煩,我嘗試了兩種使用pyqt庫來設計ui界面的方法,但由於pyqt庫太過複雜,兩種都失敗了,就是串口3和串口3’文件夾;沒辦法嘗試使用tkinter庫來設計UI界面,成功了,這就是串口4文件夾。如下:
在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述
M3M4模塊是負責本次A級實驗的串口通信模塊的下位機電路工程設計,是本次實驗的難點之一,要求配合上位機模塊實現解析控制命令、驅動採樣模塊、封裝並上傳數據等等。最難的是如何與上位機約定好協議實現數據的傳輸。這個在網上是找不到現有的工程的,也沒有能夠作爲借鑑的資料文件,真正的無中生有。從開始到結束,我和我的同伴總共寫了十一個版本,其中小的修改不計其數,最終纔得到了一個能用的串口通信模塊,並整合到了整個實驗工程模塊中。
在這裏插入圖片描述
我和我的同伴走的是兩條路,我寫的是串口工程四個文件夾,他寫的是串口通信七個文件夾,希望兩路並進來實現這個模塊。我所走的是通過增設一個字節的標誌位來傳遞幾個字節的數據,這個數據的字節數可以自己進行設定。由於一開始不知道小板子的通信是如何進行的,還是按照之前我們給的小板子進行設計,設計了一個並行通信的工程,當然是失敗了,不過還是爲測試上位機軟件做出了貢獻。然後開始在實驗板上進行設計,卻發現怎麼都不成功。最氣人的是即便在電腦上功能仿真成功了,在板子上還是不成功,用串口助手接收不到數據。
在這裏插入圖片描述在這裏插入圖片描述
這幾個文件夾先後攻克了分頻問題(分頻錯誤)、標誌位無法識別問題(時鐘不匹配導致標誌位無法正確識別)、數據傳輸問題(沒有設計好傳輸協議)、數據封裝問題(之前一直不知道需要對數據進行封裝),最終迴歸到串口工程文件夾,寫出了可以正常運行、正常數據傳輸的串口工程。
然後整合到最終結果上,設計完整的電路工程,又寫了九個,最終得到了好的結果,也算是苦盡甘來、水到渠成了,畢竟,過程再坎坷,磕磕絆絆也無所謂,把所有的坑踩遍,最後也能到達終點,而且收穫也最多。

二、所選方案和實現:
M5M6模塊上面說我寫了5個文件夾分別對串口通信、圖形繪製、UI交互三個方面進行了實現,接下來需要進行整合。一開始嘗試以串口通信爲主進行整合,卻發現沒有辦法實現UI界面,後來嘗試以UI交互界面爲主進行整合,發現很難將圖像繪製和UI界面進行整合,最終決定摒棄之前的繪圖方式,即放棄使用pygragh庫進行圖形的實時繪製,而是採用tkinter庫中的畫布函數來實現直接在UI界面中實現圖形的實時繪製,並通過定義全局變量來實現對串口通信數據的保留和保持,最終實現了上位機軟件,具體如下:
單單爲了實現整合,我就寫了十幾個文件,有複雜的有簡單的,複雜的可以到三四個文件來構成一個軟件,簡單的卻只有十幾行用來測試能否正確繪圖,最終的tkin窗口2.0和tkin窗口2.1都是成功結果,而2.1相對於2.0增加了一些花裏胡哨的音色、音量調節的功能,在後面將會提到。
這裏首先使用2.0版本的進行整體的設計和實驗,設計了開機關機按鈕和“串口號”、“波特率”、“平均值”三個標籤用來表示當前程序的狀態。設計了右側的部分進行動態圖形繪製。
具體代碼如下:

# encoding: utf-8
import tkinter
import serial
import serial.tools.list_ports
import random
import sys
import time
import easygui as g
import numpy as np
from tkinter import Tk,StringVar
from pyico import *
ser=0
pq=0
N=200
M=1
Q=0
tmp=0
ftmp=0
ii=0
r=''
rr=""
star='0'
end='0'
tt=0
L=[]
def com():
    port_list=list(serial.tools.list_ports.comports())
    if len(port_list)==0:
        g.msgbox('警告','找不到串口','拜拜了您嘞')
        return '0'
        # print('找不到串口')
    else:
        for i in range(0,len(port_list)):
            print(port_list[i])
        ss=str(port_list[0])
    return ss[0:4]
def a():
    global ii,rr,tmp,Q,ftmp,end,pq,tt,r,L
    # num=ser.inWaiting()
    # while num!=1:
    #     print(num)
    #     ss=ser.read(16)
    #     num=ser.inWaiting()
    ser.flushInput()
    num=ser.inWaiting()
    # print(num)
    data0=bytes([0x2a])
    data1=bytes([0x30])
    # data2=bytes([0x2a])
    # data3=bytes([0x00])
    # print(data0)
    # print(data1)
    ser.write(data0)
    ser.write(data1)
    num=ser.inWaiting()
    # print(num)
    # while num:
    #     num=ser.inWaiting()
    #     print(num)
    #     if num==4:
    #         ser.write(data2)
    #         ser.write(data3)
    # print(data0)
    # print(data1)
    # print(num)
    if num>0:
        # print(num)#查看當前有多少數據在緩存區
        s0=ser.read(2)
        ser.flushInput()
        # s0=ser.read(1)
        # print(s0[0],s0[1])
        # print(s1)
        if s0[0]==0:#修改點
            # print("zhi",s0[0],s0[1])
            ftmp=tmp
            # tmp=s[0]*256+s[1]
            tmp=s0[1]
            # print(tmp)
            if(len(L)==10):
                del L[0]
                L.append(tmp)
            else:
                L.append(tmp)
            if pq==0:
                ftmp=tmp
            pq=pq+1
            count=np.bincount(L)
            tmp=np.argmax(count)
            print(tmp)
            # print(pq)
            oupu.write(str(M*Q)+':'+str(tmp)+'\n')
            Q=Q+1
            win.create_line(245,ftmp*0.8,255,tmp*0.8)
            for ie in range(0,pq+1):
                win.move(ie,-6,0)
            top.update()#刷新
        # print("zhi")
        # ftmp=tmp
        # # tmp=s[0]*256+s[1]
        # tmp=s0[0]
        # print(tmp)
        # if(len(L)==10):
        #     del L[0]
        #     L.append(tmp)
        # else:
        #     L.append(tmp)
        # if pq==0:
        #     ftmp=tmp
        # pq=pq+1
        # # print(pq)
        # oupu.write(str(M*Q)+':'+str(tmp)+'\n')
        # Q=Q+1
        # win.create_line(240,ftmp+20,260,tmp+20)
def kaishi():
    global star,end
    star='start'
    print('kaishi')
    # ass=[0,1,0,1,0,1,0,1]
    data0=bytes([0x2a])
    data1=bytes([0x00])
    # print(data0)
    # print(data1)
    ser.write(data0)
    ser.write(data1)
    # data=bytes([0xE8])
    while end!='end':
        a()
    oupu.close()
def jieshu():
    global end
    print('jieshu')
    end='end'
    # ass=[1,1,1,1,1,1,1,1]
    data0=bytes([0x2a])
    data1=bytes([0xaa])
    # print(data0)
    # print(data1)
    ser.write(data0)
    ser.write(data1)
    top.quit()
def junzhi():
    global  L
    df=0
    for i in L:
        df=df+i
        ttmp=str(df/len(L))
    # ttmp='123456'
    Label4=tkinter.Label(top,text="平均值:"+ttmp,fg='black')#bg='light gray',
    Label4.place(relx=0.1,rely=0.3)
ssss=com()
if ssss!='0':
    top=tkinter.Tk()
    top.title('波形顯示串口助手')#標題
    top.resizable(0,0)#大小可調性
    top.geometry('500x300')#大小
    bote=9600
    oupu=open('output1.txt','w')
    ser = serial.Serial(ssss, bote)
    Label1=tkinter.Label(top,text=("串口號:"+ssss),fg='black')#bg='light gray',
    Label1.place(relx=0.1,rely=0.1)
    Label2=tkinter.Label(top,text="波特率:"+str(bote),fg='black')#bg='light gray',
    Label2.place(relx=0.1,rely=0.2)
    Label3=tkinter.Label(top,text="平均值:",fg='black')#bg='light gray',
    Label3.place(relx=0.1,rely=0.3)
    button1=tkinter.Button(top,text="開機",command=kaishi,bg='light gray',fg='black')
    button1.place(relx=0.1,rely=0.45,width=80,height=40)
    button2=tkinter.Button(top,text="關機",command=jieshu,bg='light gray',fg='black')
    button2.place(relx=0.1,rely=0.6,width=80,height=40)
    button3=tkinter.Button(top,text="均值",command=junzhi,bg='light gray',fg='black')
    button3.place(relx=0.1,rely=0.75,width=80,height=40)
    win=tkinter.Canvas(top,bg='light gray')
    win.place(relx=0.35,rely=0.1,width=310,height=240)
    top.update()#刷新
    top.mainloop()

其中包含了大量的註釋掉的程序語句,因爲在我將整個程序的整體框架確定下來之後,對這個程序調試了很多遍,最終得到的代碼行數實際上只有100行左右,但功能卻能完整的實現。
M3M4首先對單個的串口工程進行實驗,最終選定的方案是設置標記位爲“01010100”,然後在串口工程中先搜索接受的上位機數據中有沒有“010”的三位二進制數,如果找到就再搜索有沒有“00”的二進制數,如果找到則說明找到了標誌位,“00”之後的八位二進制數就是上位機傳給下位機的真正數據。然後上傳給上位機的時候,一開始沒有注意到需要對數據進行封裝,還是嘗試着先發八個二進制“00000000”作爲標誌位,再跟上八位二進制的數據,但怎麼也傳不上去,後來在科三的同學的幫助下,知道了需要對數據進行封裝,每八位數據需要在最前面加0,在最後面加1,將原本的8位數轉換爲10位數後纔可以讓芯片進行識別,將中間的8位數據傳送給上位機,最終得到的串口工程如下:
在這裏插入圖片描述
fenpin模塊負責將輸入的24Mhz的輸入信號轉換爲9600hz的時鐘信號,用來控制數據的傳輸。jieshou模塊負責接收從上位機發送的數據,併產生相應的kj開機控制信號和load數據上傳控制信號。chuansong模塊負責接收外界給的八位二進制數據,進行封裝之後在load和kj控制信號的控制下傳遞給上位機,這裏只截取了三個元件中的部分主要代碼,因爲截取全部代碼太佔據空間了,而且所截取的代碼是功能的主要實現部分,已經可以體現如何實現功能模塊。
具體模塊如下:
在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述

三、驗證方法:
M5M6模塊基於pycharm軟件進行設計,總共調用了Python語言的tkinter庫、serial庫、random庫、sys庫、time庫、easygui庫、numpy庫、pyico庫八個庫,具體框架爲通過tkinter庫來設計UI交互界面,通過tkinter庫中的canvas庫設計畫布,通過move函數實現動態繪圖,通過serial庫實現串口讀寫操作,通過easygui庫實現警告信息,通過numpy庫實現數值穩定,通過random庫實現功能測試。
首先要驗證整個軟件的模塊邏輯是否正確。本軟件的邏輯爲:首先通過com()函數自動查找當前可用於通信的串口,如果沒有將會彈出一個easygui的彈窗,否則將會彈出軟件的UI操作界面。界面有開機按鈕、關機按鈕和取平均值按鈕,當選擇開機按鈕後將會給予下位機開機指令,並進入循環,持續向下位機發送請求數據的指令,並接收下位機發送的數據,經過取衆數處理後從最近的10箇中取出衆數(以此來提高軟件的抗干擾能力),並繪製圖像顯示在右側;選擇關機按鈕後將會向下位機發送關機指令,並自動關閉彈窗;當選擇取均值按鈕後將會自動計算最近10個數的平均值,並顯示在界面指定位置。界面指定位置會顯示當前的串口和預置的波特率(9600)。
在測試方面基於小板子,首先測試串口是否正常打開,然後通過random函數向板子發送一個上位機隨機生成的數值,傳給下位機後下位機進行顯示,並原封不動的傳給上位機,在上位機的數值顯示部分進行圖形的繪製,這裏先註釋掉了取平均值的功能,並選擇了115200的波特率用來簡單測試。最終得到的結果如下:
在這裏插入圖片描述在這裏插入圖片描述
在小板子上初步實現了之後,開始思考波特率的問題。由於下位機模塊的數據讀取是在1Mhz,而板子給定的時鐘是24Mhz,經過與下位機模塊負責人討論後確定使用9600波特率,即一秒鐘傳送9600位,這樣只需要將原本的24Mhz除以2500就可以得到9600hz的時鐘信號。經過在給定的實驗板上進行測試,發現正確,至此,上位機需要做的事情已經基本完成。
M3M4這裏首先對所編寫工程的邏輯性進行驗證分析。首先初始狀態kj開機控制信號的寄存器爲‘0’,load裝載控制信號的寄存器爲‘0’,表示此時沒有開機,也沒有進行裝載操作,不會向上位機發送特定數據(注意,還是會發送無意義的數據),而此時上位機也處於待機狀態,不會接受特定數據(串口會持續發送默認的“11111111”),然後上位機給予開機信號,接收模塊接收到後控制kj開機控制信號寄存器爲‘1’,表示開機,整個工程開始工作。當上位機發送數據傳送控制信號的時候,接收模塊接收到後控制load裝載控制信號寄存器爲‘1’,表示開始裝載,傳送模塊將外部輸入的八位數據存儲到寄存器中,並進行封裝,然後將標記位也進行封裝,最終得到一個二十位的二進制數據,傳送給芯片,並最終傳送到電腦,展示在串口助手上。
然後進行功能仿真,並最終放到整個工程中進行驗證,發現結果正確,可以在上位機接收到數據,並展示在圖像上。
這裏需要考慮時鐘信號的問題,上位機的波特率限定爲9600,傳入的時鐘頻率爲24Mhz,所以需要除以2500才能得到正確的時鐘信號,這裏只需要寫一個計數器,要求每個時鐘上升沿進行計數,當記錄到1250的時候進行清零,然後將輸出信號取反就可以得到9600hz的時鐘信號。
然後由於需要在整個電路上進行驗證,所以需要添加到整個的工程文件上,即封裝爲bsf元件,然後與整個電路進行串聯,最終得到的電路和運行結果如下:
在這裏插入圖片描述
在這裏插入圖片描述
四、下一步工作:
M5M6下一步可以在現有的基礎上加一些花裏胡哨的東西,來使UI界面更友好,即可以改變背景圖片,改變UI界面的格式,增加音量音色調節按鈕等等,期望實現的結果如下:
在這裏插入圖片描述
當前 1
在這裏插入圖片描述
期望 1
增加“小、中、大”的音量調節按鈕和“1,、2、3、4”的音色調節按鈕,最好可以和蜂鳴器模塊負責的同學一起設計幾首歌放入mif文件來進行顯示。
M3M4模塊通過測試發現雖然已經實現了串口通信,完成了A級實驗,但當前工程的抗干擾能力不強,很容易受到機械噪音的影響導致繪製出來的圖像有偏差。所以下一步工作可以嘗試着從提高信號穩定性、增強通信穩定性、修改傳遞方式的傳遞數據、提高數據接收、數據讀取、數據採集靈敏度等方面進行優化。
甚至可以通過上位機來輸入數據實現一個電子琴的效果,當然,這是後話。

五、心得體會
本次設計總結:
這次的大綜合實驗很考驗人,我和我的搭檔俞陽博因爲之前有學習過Python語言所以選擇了上位機軟件設計M5M6模塊。實際上選擇的時候心裏也沒有底氣,因爲要我們設計軟件,真的太難了,但別人更沒有基礎,所以還是去做了。一開始還抱着從網上找現成代碼進行修改的想法,所以找了很多,不得不說csdn還是真的很厲害的,竟然找到了很多,但要麼是沒有串口通信模塊,要麼是沒辦法繪圖,所以到最後實際上還是自己設計,不過從網上得到了很多的知識,對Python庫的理解與應用也強了很多。到最後設計的串口助手是我自己真真正正一個人完成的,沒有任何網上的代碼,包括串口搜索、串口通信、動態繪圖,都是我自己原創的想法。總的來說,Python語言進步了很多。
然後由於下位機通信模塊和上位機軟件模塊連接非常緊密,而且下位機通信模塊比較難,所以我就參與了下位機通信模塊的設計,而且採用了和原本同伴並不同的方法,後來證實我的方法是正確的。而且這一部分告訴了我很多,如何進行通信,如何進行封裝,爲何要進行封裝,以及如何進行上傳下放,爲我小學期打下了很好的基礎。
學期總結:
這門實驗課讓我進步良多,也讓我花費了很多時間,單說最後一個大綜合實驗,整個實驗從頭到尾做了兩個多周,從5月6號開始創建了綜合實驗的文件夾開始,一直沒停過,從早上八點到晚上十點整天泡在實驗室,餓了就叫外賣,直到要睡覺了纔回宿舍,說真的我都想打地鋪住在實驗室算了。這門實驗課很好玩,能做很多真真正正的事情,感覺自己學習的東西真的有用,能夠用在實際生活中,能夠做一些實實在在的事情,也讓我對我的小學期充滿了期待。
這門實驗課我的參與度很高,我也是真的喜歡這個實驗,纔會願意花這麼多時間去做。而且,說真的,我很喜歡實驗室的環境,特別是五一假期的時候。五一假期我哪裏也沒有去,四天全都泡在了實驗室裏,沒有一直在敲代碼,而是寫一寫別的事情,也覺得自己的效率很高,實驗室的環境真的很喜歡,也很適合我,那個五一假期也是我最充實的一個假期。
在實驗室裏能讓我感覺得平靜、積極,也能讓我更專注於我目前正在做的事情,不管是敲代碼還是記筆記,都是如此。現在很慶幸當初將自己的指紋錄入在了系統裏面,或許以後實驗室可以作爲一個我的自習的地方。
我早就從學長學姐那裏聽說了,小學期也是在工訓,也是給一塊板子讓我們自己做一個工程出來,而且是隨便做,想做什麼做什麼,上一屆就有學長學姐做了密碼鎖、遊戲機什麼的,我自認爲比不上上一屆的學長學姐,但我也有我自己的想法。既然已經可以實現串口通信,那麼我對製作一個密碼鎖已經充滿了信心,所以我想先做一個密碼鎖來保底,能夠完成小學期,然後自己再開始自己的研究,我真正想做的是一個機械手,用我的電腦進行控制,或者更進一步,我在我的手上帶一個手套,然後通過測距將信息傳遞給下位機,下位機來做出相似的動作。這個很難,但如果只是簡單的完成實驗作業,就談不上研究了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章