真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

python怎么實(shí)現(xiàn)串口通信-創(chuàng)新互聯(lián)

這篇文章主要介紹了python怎么實(shí)現(xiàn)串口通信,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

創(chuàng)新互聯(lián)建站是專業(yè)的牧野網(wǎng)站建設(shè)公司,牧野接單;提供成都網(wǎng)站制作、成都做網(wǎng)站,網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行牧野網(wǎng)站開(kāi)發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛(ài)的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!

1 硬件設(shè)備

  • TTL串口攝像頭(VC0706)

  • USB轉(zhuǎn)TTL燒錄器

2 serial安裝

第一次安裝的是serial的包導(dǎo)包的時(shí)候發(fā)現(xiàn)下載錯(cuò)了,正確應(yīng)該是pyserial。安裝后直接import就可以了。

3 實(shí)現(xiàn)串口通信

3.1 發(fā)現(xiàn)端口

Windows下為COM(N, N=1、2...), Ubuntu下為‘/dev/ttyS0'。Windows初學(xué)者,可以給您一下兩種方式確定端口號(hào)。

方法一:輸入在終端(cmd)中輸入

python -m serial.tools.list_ports

輸出結(jié)果:

COM5
1 ports found

方法二:搜索電腦上的設(shè)備管理器,打開(kāi)以后然后插入燒錄器,自動(dòng)就會(huì)彈出。如果沒(méi)有彈出就可能是驅(qū)動(dòng)沒(méi)有安裝,安裝好以后不好使,重啟一下電腦,到了工作的時(shí)候大家都知道程序員會(huì)跟你說(shuō),你重啟一下,清一下緩存,這兩句話。也有可能是驅(qū)動(dòng)安裝的不對(duì)。

python怎么實(shí)現(xiàn)串口通信

方法三:直接找一個(gè)有端口掃描的上位機(jī),點(diǎn)擊掃描就可以了。大部分上位機(jī)都是你一插進(jìn)去就會(huì)檢測(cè)到你的端口。

python怎么實(shí)現(xiàn)串口通信----->python怎么實(shí)現(xiàn)串口通信

注意:當(dāng)串口被占用的時(shí)候也有可能導(dǎo)致失敗,例如你在編譯器有兩個(gè)進(jìn)程運(yùn)行下面的測(cè)試代碼,第二個(gè)進(jìn)程就會(huì)因?yàn)槎丝谡加枚?。也有的上位機(jī)是因?yàn)橥瑫r(shí)打開(kāi)了兩個(gè)上位機(jī)的緣故(實(shí)驗(yàn)課的時(shí)候同學(xué)遇到過(guò)情況),可以用任務(wù)管理器kill掉。

測(cè)試:

import serial
 
 
#Windows
ser = serial.Serial(port='COM5', baudrate=115200, timeout=0.5)
print(ser.name)

控制臺(tái)打印結(jié)果: 

COM5
Process finished with exit code 0

建立ser對(duì)象的代碼:

class PicSerial:
  __ser = None # ser的單例
  __isinit = False
 
  @staticmethod
  def get_available_port():
    """
    檢測(cè)可以使用的端口號(hào)
    :return->str: 端口號(hào)的名稱
    """
    port = list(list_ports.comports())
    if len(port) > 0:
      port_name = port[0].device
      print(port_name)
      return port_name
      # logging.info("Available port:", ports)
    else:
      print("There is no available port.")
      # logging.error("There is no available port.")
 
  def __new__(cls, *args, **kwargs):
    if PicSerial.__ser is None:
      cls.__ser = object.__new__(cls)
    return cls.__ser
 
  def __init__(self):
    if not PicSerial.__isinit:
      self.sername = self.get_available_port()
      self.ser = serial.Serial(port=self.sername, baudrate=BAUDRATE)
      PicSerial.__isinit = False
      print("PicSerial init.")

3.2 發(fā)送命令

3.2.1 協(xié)議格式

python怎么實(shí)現(xiàn)串口通信

3.2.2 serial傳送的方式

serial傳送的方式有:

串行端口對(duì)象。只傳單個(gè)字節(jié)。字符串。字節(jié)數(shù)組+字節(jié)數(shù)組長(zhǎng)度。

所以直接選用數(shù)組傳數(shù)據(jù),這里會(huì)遇到一個(gè)問(wèn)題就是python的list會(huì)自動(dòng)把十六進(jìn)制數(shù)轉(zhuǎn)換為整形。

python怎么實(shí)現(xiàn)串口通信

所以要進(jìn)行轉(zhuǎn)換你可以直接寫(xiě)成b“/x56/x00/x17/x00”。假如你不需要傳十進(jìn)制也可以轉(zhuǎn)成list,直接map(chr,x)或map(ord,x)也是可以的。讀的時(shí)候也要注意只要你放進(jìn)list里面就會(huì)自動(dòng)轉(zhuǎn)成整形。

【我覺(jué)得這樣寫(xiě)很降智,但是又不得不這樣寫(xiě)】

 #在PicSerial中
  def isreply(self, cmd: bytes, option: str) -> bool:
    """
    檢測(cè)是否有回復(fù)
    :return:回復(fù)的內(nèi)容
    :param cmd:
    :param option:
    :return: True則有回復(fù)
    """
    if isinstance(cmd, bytes) and isinstance(option, str) and len(cmd) > 0 and len(option) > 0:
      self.ser.write(cmd)
      reply = self.ser.read(4)
      reply = list(map(chr, list(reply)))
      print("49h,The function'{}' is running. reply:{}".format(sys._getframe().f_code.co_name, reply))
      if len(reply) >= 4 and reply[0] == 'v' and reply[1] == SERIAL_NUM and reply[2] == option and reply[3] == STATUS:
        return True
    return False

測(cè)試:

#在test文件中
class TestSerial(unittest.TestCase):
  def test_isreply(self):
    self.assertTrue(ser.isreply(GET_VERSION_CMD, VERSION))
    self.assertFalse(ser.isreply('\x56\x00\x11\x00', VERSION))
    self.assertFalse(ser.isreply(GET_VERSION_CMD, b'\x11'))
    self.assertFalse(ser.isreply(123456, b'\x11'))
    self.assertFalse(ser.isreply('', VERSION))
    self.assertFalse(ser.isreply(b'', VERSION))
    self.assertFalse(ser.isreply(GET_VERSION_CMD, ''))
    self.assertFalse(ser.isreply(GET_VERSION_CMD, None))
    self.assertFalse(ser.isreply(b'', ''))
    self.assertFalse(ser.isreply(b'\x56\x00\xAA\x00', VERSION))
    self.assertFalse(ser.isreply(GET_VERSION_CMD, '\xAA'))
 
 
#之后就省略不寫(xiě)了
if __name__ == '__main__':
  unittest.main()

結(jié)果:

python怎么實(shí)現(xiàn)串口通信

3.3 獲取版本號(hào)(hello world)

按照協(xié)議一步一步操作

主 機(jī) 發(fā):56 00 11 00 攝像頭回:76 00 11 00 0B 56 43 30 37 30 33 20 31 2E 30 30 (VC0703 1.00)

#在PicSerial中
  def getversion(self) -> str:
    """
    獲取版本號(hào)
    :return:
    """
    cmd = GET_VERSION_CMD
    option = VERSION
    if self.isreply(cmd, option):
      left = self.ser.readall()
      print("75h,The function'{}' has responded.left{}".format(sys._getframe().f_code.co_name, left))
      return self.ser.read(12).decode()[1:]

測(cè)試:

#在test文件中
  def test_getversion(self):
    self.assertEqual(ser.getversion(), 'VC0703 1.00')

結(jié)果:通過(guò)測(cè)試

3.4 復(fù)位

主 機(jī) 發(fā): 56 00 26 00

攝像頭回: 76 00 26 00 00

#在PicSerial中
  def reset(self):
    """
    復(fù)位
    :return:
    """
    cmd = REST_CMD
    option = RESET
    if self.isreply(cmd, option):
      if self.ser.read(1) == b'':
        left = self.ser.readall()
        print("75h,The function'{}' has responded.left{}".format(sys._getframe().f_code.co_name, left))
        return True
    return False

*測(cè)試和運(yùn)行結(jié)果不一樣。

python怎么實(shí)現(xiàn)串口通信

python怎么實(shí)現(xiàn)串口通信

花了一點(diǎn)時(shí)間找到原因了,單元測(cè)我都是點(diǎn)擊前面綠色的小箭頭,以為只是運(yùn)行當(dāng)前的測(cè)試函數(shù)的內(nèi)容,但是我發(fā)現(xiàn)它把其他的函數(shù)都運(yùn)行了。所以要把之前的測(cè)試函數(shù)注釋掉得到的結(jié)果就一樣了。

python怎么實(shí)現(xiàn)串口通信

測(cè)試通過(guò)。

3.5 照相

  • 停止當(dāng)前幀刷新

  • 獲娶圖片長(zhǎng)度

  • 獲取圖片

  • 恢復(fù)幀更新

3.5.1 停止當(dāng)前幀刷新

這一步執(zhí)行一次就夠了。因?yàn)樽x命令的時(shí)候會(huì)出現(xiàn)麻煩。但是這一步是有意義的,就是當(dāng)你發(fā)現(xiàn)圖片很大,的時(shí)候正常大小就兩個(gè)byte可以表示完了(排除你的圖片面積十分大或十分清晰),又或者是突然讀空了。假如數(shù)值非常的大,可以使用該函數(shù),再不行就要選擇復(fù)位。

 def stoprefresh(self):
    """
    停止刷新當(dāng)前幀
    :return:
    """
    cmd = STOP_REFRESH_CMD
    option = TAKE_PHOTO
    self.ser.write(cmd)
    if self.isreply(cmd, option) and self.ser.read(1) == b"\x00":
      left = self.ser.readall()
      print("87h,The function'{}' has responded.left{}".format(sys._getframe().f_code.co_name, left))
      return True
    return False

通過(guò)測(cè)試

 def test_stoprefresh(self):
    self.assertTrue(ser.stoprefresh())

3.5.2 獲娶圖片長(zhǎng)度

  def getlength_bytes(self) -> bytes:
    """
    獲取圖片的長(zhǎng)度
    :return:
    """
    cmd = GET_LENGTH_CMD
    option_pic = '4'
    self.ser.write(cmd)
    if self.isreply(cmd, option_pic):
      if self.ser.read(1) == b'\x04':
        res = self.ser.read(4)
        left = self.ser.readall()
        print("103h,The function'{}' has responded.left{}".format(sys._getframe().f_code.co_name, left))
        return res
    return b'\x00\x00\x00\x00'

測(cè)試通過(guò)

def test_getlength(self):
    self.assertEqual(ser.getlength(), b'\x00\x00\x12\x34')

3.5.3 恢復(fù)幀更新

 def recover_refresh(self):
    """
    恢復(fù)幀刷新
    :return:
    """
    cmd = RECOVER_REFRESH_CMD
    option = TAKE_PHOTO
    self.ser.write(cmd)
    if self.isreply(cmd, option):
      # 讀出剩余的字節(jié)
      left = self.ser.readall()
      print("142h,The function'{}' has responded.left{}".format(sys._getframe().f_code.co_name, left))
      return True
    return False

測(cè)試并通過(guò):

def test_recover_refresh(self):
    self.assertTrue(ser.recover_refresh())

3.5.4 拍照

在這里卡了很長(zhǎng)時(shí)間,不知道為什么長(zhǎng)度是不確定的,每一次讀的長(zhǎng)度都沒(méi)讀完,看代碼。

下面代碼只是演示

#下面代碼只是演示不在最終版本中 
  def savephoto(self, cmd, option, len):
    """
    保存圖片
    :param cmd:
    :param option:
    :param len: 照片的長(zhǎng)度
    :return:
    """
    with open('write_pic/serialpic/photo.jpg', 'wb') as f:
      if self.isreply(cmd, option):
        print(self.ser.read(1))
      countofread_complete_byte = 0 # 用于計(jì)算當(dāng)前已經(jīng)寫(xiě)入的長(zhǎng)度
      while countofread_complete_byte != len + 10:
        # read()是有上限的,不可以把全部都讀取
        lines = self.ser.read(len + 10 - countofread_complete_byte)
        countofread_complete_byte += lines.__len__()
        f.write(lines)
        print("142h,countofread_complete_byte:", countofread_complete_byte, "lines", lines.__len__())
      left = self.ser.readall()
      print("146h,少讀內(nèi)容:", left, "共", left.__len__(), "個(gè)字節(jié)")
    res = self.ser.readall()
    print(res)

現(xiàn)象:

現(xiàn)象是運(yùn)行一直不停都是手動(dòng)stop console,或者沒(méi)有stop console會(huì)一直打印lines為空,就此可以猜測(cè)read()不是阻塞的。是圖片字節(jié)總數(shù)不斷增多。每次遍歷完后滿足self.ser.read(len + 10 - countofread_complete_byte)后再readall()還是有剩余的內(nèi)容。

python怎么實(shí)現(xiàn)串口通信

python怎么實(shí)現(xiàn)串口通信

我發(fā)現(xiàn)此時(shí)readall一共讀出了4049個(gè)字節(jié),圖片數(shù)據(jù)4030個(gè)字節(jié)+首尾兩部分共10個(gè)字節(jié),那多出來(lái)的9個(gè)字節(jié)是什么火眼金睛的Unyielding ● L發(fā)現(xiàn)了正確的開(kāi)始位置為上圖紅色方塊處,碰巧多出來(lái)的是九個(gè)字節(jié),所以多出來(lái)的就不是這一張圖片的內(nèi)容,所以可以猜想程序沒(méi)有停止的原因是上一次圖片還沒(méi)讀完我就手動(dòng)停止,所以留下了數(shù)據(jù),上一次沒(méi)有讀完的內(nèi)容,這一次讀到了。

字節(jié)串和字符串都可以切片。直接切出來(lái)保存。

 def getphoto(self):
    """
    拍照并且保存圖片
    :return:
    """
    # self.reset()
    # 1、停止幀刷新
    # self.stoprefresh()
 
    # 獲取圖片長(zhǎng)度
    # 返回字節(jié)長(zhǎng)度用于整合命令,表示圖片的總字節(jié)數(shù)
    length = self.getlength_bytes()
    # 返回整形,表示圖片的總字節(jié)數(shù)
    len = self.bytesToInt(length)
    print("158h,len:", len)
 
    # 拍照
    cmd = GET_PHOTO_START_CMD + length + GET_PHOTO_END_CMD
    print("159hcmd", cmd)
    self.ser.write(cmd)
 
    readall = self.ser.readall()
    readall_len = readall.__len__()
    differ = readall_len - len - 10
    if differ != 0:
      res = readall[differ + 5:-5]
      print("172h:", res)
      self.savephoto(res)
    else:
      res = readall[5:-5]
      print("175h:", res)
      self.savephoto(res)
 
    # 關(guān)閉串口
    self.ser.close()
 
    # 恢復(fù)刷新
    # self.recover_refresh()

成功輸出結(jié)果:

python怎么實(shí)現(xiàn)串口通信

為了方便debug,停幀回復(fù)幀都是手動(dòng)發(fā)送的,剩下的問(wèn)題就是把注釋打開(kāi)試一試能不能成功組合成一個(gè)函數(shù),發(fā)現(xiàn)有的命令會(huì)讀空,所以可以推斷:一定又是前一個(gè)命令里面又留下來(lái)什么還沒(méi)有被讀取的字節(jié)造成讀到的內(nèi)容篡位了。

python怎么實(shí)現(xiàn)串口通信

每一次執(zhí)行完命令后看一看還有沒(méi)有遺留字節(jié),把剩余字節(jié)都取出來(lái),然后differ的判斷都不需要了?!咀x者看到的代碼都是最新版本的,此處我添加了left和print到對(duì)應(yīng)函數(shù)中】,處理結(jié)果打印到控制臺(tái):

python怎么實(shí)現(xiàn)串口通信

def getphoto(self):
    """
    拍照并且保存圖片
    :return:
    """
    # 1、停止幀刷新
    self.stoprefresh()
 
    # 獲取圖片長(zhǎng)度
    # 返回字節(jié)長(zhǎng)度用于整合命令,表示圖片的總字節(jié)數(shù)
    length = self.getlength_bytes()
    # 返回整形,表示圖片的總字節(jié)數(shù)
    len = self.bytesToInt(length)
    print("161h,The function'{}' is running. len:{}".format(sys._getframe().f_code.co_name, len))
 
    # 拍照
    cmd = GET_PHOTO_START_CMD + length + GET_PHOTO_END_CMD
    print("165h,The function'{}' is running. cmd:{}".format(sys._getframe().f_code.co_name, cmd))
    self.ser.write(cmd)
 
    readall = self.ser.readall()
    readall_len = readall.__len__()
    differ = readall_len - len - 10
    if differ != 0:
      res = readall[differ + 5:-5]
      print("161h,The function'{}' is running. res:{}".format(sys._getframe().f_code.co_name, res))
      self.savephoto(res)
    else:
      res = readall[5:-5]
      print("161h,The function'{}' is running. res:{}".format(sys._getframe().f_code.co_name, res))
      self.savephoto(res)
 
    # 恢復(fù)刷新
    self.recover_refresh()

輸出圖片結(jié)果(拍的是導(dǎo)線沒(méi)有聚焦)

python怎么實(shí)現(xiàn)串口通信

python怎么實(shí)現(xiàn)串口通信

# 這個(gè)測(cè)試應(yīng)該怎么寫(xiě)? 有圖片就輸出并且可以打開(kāi)就可以了惹?有人能教教我?
  def test_getphoto(self):
    pass

python怎么實(shí)現(xiàn)串口通信

 4 反思犯了很多

‘我覺(jué)得'的錯(cuò)誤,我覺(jué)得這個(gè)值是什么,多打斷點(diǎn)看清楚,那一段演示代碼里面因?yàn)閰f(xié)議寫(xiě)了是五個(gè)字節(jié),isreply我已經(jīng)讀了4個(gè)字節(jié)再讀一個(gè)一定是0x00,后來(lái)打印那一行返回的值是0x04這才為猜想讀到上一張圖作下鋪墊。

當(dāng)你寫(xiě)的很復(fù)雜超過(guò)20行的邏輯代碼就知道一定是錯(cuò)了。--UnyieldingL

編碼方面的內(nèi)容耗費(fèi)了很長(zhǎng)時(shí)間,就在反思的時(shí)候發(fā)現(xiàn)了decode("hex")。惹?

list='aabbccddee' 
hexer=list.decode("hex") 
print hexer

打印日志要詳細(xì)。 每一個(gè)變量涉及的變量長(zhǎng)度函數(shù)名,此時(shí)哪個(gè)函數(shù)運(yùn)行。

還有一個(gè)問(wèn)題,pycharm還是沒(méi)有自己停止,打印某個(gè)線程的堆棧。

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“python怎么實(shí)現(xiàn)串口通信”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持創(chuàng)新互聯(lián)成都網(wǎng)站設(shè)計(jì)公司,關(guān)注創(chuàng)新互聯(lián)成都網(wǎng)站設(shè)計(jì)公司行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來(lái)學(xué)習(xí)!

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、網(wǎng)站設(shè)計(jì)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。


網(wǎng)站欄目:python怎么實(shí)現(xiàn)串口通信-創(chuàng)新互聯(lián)
路徑分享:http://weahome.cn/article/cdhcgi.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部