通过串口烧入hex到pic单片机(pic已经运行boot程序)
down_hex.py 源码
#coding:utf-8
import serial
import pic_hex_pars
import time
from threading import Timer
#串口定时接收
class PicSerial():
def __init__(self):
self.t = Timer(0.02, self.func)
self.t.start()
self.ser=serial.Serial("com1", 57600, timeout=0.5)
self.rx_data=[0,0,0,0,0,0,0,0]
def func(self):
try:
num = self.ser.inWaiting()
except:
t.ser.close()
return None
if num > 0:
self.rx_data = self.ser.read(num)
num = len(self.rx_data)
# print(num)
# print(self.rx_data[0],self.rx_data[1])
# print("com2接收:",rx_data.decode('iso-8859-1'))
# print(self.rx_data)
self.t.cancel()
self.t = Timer(0.02, self.func)
self.t.start()
PROGRAM_DEVICE_CMD=[0xD0,0XF2,0X05,0X00,0X20,0X00,0X00,0X36,0X37,0X38] ### 烧写程序命令,PROGRAM_DEVICE_CMD【00 20 00 00 表示起始地址0x00002000(左边为低字节)】
hex_data,start_addr=pic_hex_pars.hex_pars() #读取代码数据
print("编程地址:", hex(start_addr))
print("转换后的代码行数:",len(hex_data))
# 从hex中获取代码起始地址
addr_l=start_addr%256
addr_h=start_addr//256
PROGRAM_DEVICE_CMD[3] = addr_l
PROGRAM_DEVICE_CMD[4] = addr_h
pic_ser = PicSerial() #打开串口
pic_ser.ser.write(PROGRAM_DEVICE_CMD) #开始烧写程序命令,指定了烧写起始地址
time.sleep(1)#等待命令完成
for i in range(0, len(hex_data)):
data=bytearray.fromhex(hex_data[i])
print("第",i,"帧下载中:", hex_data[i],"\n\r")
pic_ser.ser.write(data) # 写8字节程序数据到单片机
#等待一帧数据下载完成
while pic_ser.rx_data[0]!=54 or pic_ser.rx_data[1]!=54:
0
# print(t.rx_data[0], t.rx_data[1], t.rx_data[2])
print("第",i,"帧下载完成!块填充计数监控值:", pic_ser.rx_data[2],"\n\r") #打印提示信息
pic_ser.rx_data =[0,0,0,0,0,0,0,0]
print("hex发送完成")
pic_hex_pars.py 源码
#coding:utf-8
import binascii
import os
import linecache
#检查校应码
def calc_checksum( data):
checksum = 0
result=0
# print("校应数据长度:",len(data))
for i in range(0, len(data),2):
checksum = ((int(data[i:i +2], 16))+checksum )
# print(checksum)
result=(256-checksum)&0xff
# print(result)
return result
def hex_pars(path="./led.hex"):
DOWN_DATA_CMD = [0xD0, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,0xFF] ###写ROM指令:【D0 F1 FF FF FF FF FF FF FF FF】, FF FF FF FF FF FF FF FF 表示要写入的数据数据(左边为低
hex_result = [] #存储解析结果
start_addr=0
linenum=0
data_line_num=0
file_path = path
fptr = open(file_path, "r")
while True:
line = fptr.readline().upper() ###读取一行文本,并且小写字母转大写字母
line = line.strip() ##删除头尾空格和换行符
if len(line) != 0:
# print(line)
length = int(line[1:3], 16)
addr = int(line[3:7], 16)
rtype = int(line[7:9], 16)
checksum = calc_checksum(line[1:-2])
# print("校应和:", hex(checksum))
if checksum == int(line[-2:], 16):
# print("校验正确",linenum)
# 校验正确。
if rtype == 0x00 and addr > 0 and length > 0:
data_line_num+=1
#取得hex代码的起始地址
if data_line_num ==1 :
start_addr=addr
data_len = length
send_times = (length // 8) if length % 8 == 0 else (length // 8 + 1)
# print("大循环次数", send_times)
#8字节为单位遍历一行数据
for j in range(0, send_times):
#遍历16进制字符串转字节数组,提取一行中的8字节数据
for i in range(0, 8):
if data_len != 0:
data_len = data_len - 1
# print(i)
DOWN_DATA_CMD[2 + i] = int(line[(9 + i * 2 + j * 16):(11 + i * 2 + j * 16)], 16)
# 提取数据到二维数组
# 追加(一个编程指令)到二维数组
hex_result.append(bytearray(DOWN_DATA_CMD).hex())
# print("提取8字节数据:", bytearray(DOWN_DATA_CMD).hex())
else:
print("数据不符合要求,行号:", linenum)
else:
print("校应失败,行号:", linenum)
else:
block_num=len(hex_result)//8 # 完整块数量(64字节等于一个块)
debris_num=len(hex_result)%8 # 剩余行数(一个行等于8字节,需要补齐到64字节)
# print("hex转换完成,完整块数量:",block_num,"剩余行数:",debris_num)
lack_line_number=8-debris_num #计算需要补齐多少行
#补齐缺少行
for j in range(0, lack_line_number):
hex_result.append(bytearray([0xD0, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]).hex())
for j in range(0, len(hex_result)):
print(hex_result[j])
print("转换后的代码行数:", len(hex_result))
break
linenum += 1
return hex_result,start_addr
运行示例(如下图):
一帧发送8字节数据。PIC_BOOT 需要接收64字节才写入ROM。
led.hex文件内容
:040000002CEF10F0E1
:10200000000E026E000E016E400E015C1F0E0258A3
:10201000D8B01200000E046E000E036E045007E1EB
:10202000280E035CD8B003D0034A042AF7D7014A2C
:10203000022AEAD7000E826E000E8B6E000E946E9E
:10204000010E8B6E00EC10F0000E8B6E00EC10F0A9
:0E205000F7D700F000F000F000011AEF10F0DA
:020000040020DA
:08000000FFFFFFFFFFFFFFFF00
:020000040030CA
:0E00000011087F7CFF0F81FF0FC00FE00F4043
:00000001FF