在Linux上快速搭建8051开发环境

在Linux上快速搭建8051开发环境(2018-7-2)

GitHub仓库

0. 写在开始之前

实验操作系统环境: Ubuntu 16.04

编译器: sdcc

SDCC - Small Device C Compiler是一个开源的编译器,可以去官网查看它的详细信息。sdcc提供包括linux, Windows, Mac OS X的版本。

烧录工具: stcflash

stcflash是一个开源python烧录脚本,可以非常好的支持STC系列的单片机,由于没有其他品牌的单片机所以无法保证所有51内核的单片机都可以使用。

因为这个脚本是python编写的所以windows需要安装python环境,而linux系统一般都自带python。Python版本必须高于2.6。
由于Python没有自带pySerial模块,但是烧录工具需要使用这个模块所以需要手动安装,在Ubuntu可以使用apt安装:

$ sudo apt-get install python-serial

1. 编译器安装

源码编译(可选)

若有兴趣,精力,时间可以选择源码编译安装,本咸鱼在此不多阐述。

下载二进制包

下载地址

根据具体情况下载,64位linux系统可以下载Linux on AMD64 Sempron(amd64-unknown-linux2.5)

解压到合适的目录(/opt/)

解压到自己满意地方,我比较中意/opt目录:

$ sudo tar -xjvf sdcc-snapshot-amd64-unknown-linux2.5-20180701-10463.tar.bz2 -C /opt/

添加环境变量

如果不添加环境变量,每次编译器的时候都需要输入绝对路径比较麻烦。

修改~/.bashrc来添加环境变量:

$ echo "export PATH=/opt/sdcc/bin:$PATH" >> ~/.bashrc

!PATH中的路径应该是自己解压二进制包的地方。

刷新bash:

$ source ~/.bashrc

检查是否安装成功:

$ sdcc --version
SDCC : mcs51/z80/z180/r2k/r3ka/gbz80/tlcs90/ds390/pic16/pic14/TININative/ds400/hc08/s08/stm8 3.7.1 #10463 (Linux)
published under GNU General Public License (GPL)

如果有以上信息提示,则表明安装完成。

2. 编写测试代码

/sdcc/share/sdcc/include/mcs51有很多定义好的头文件,我们使用8052.h可以满足一般的需要了。

8052.h
/*-------------------------------------------------------------------------
   8052.h: Register Declarations for the Intel 8052 Processor

   Copyright (C) 2000, Bela Torok / bela.torok@kssg.ch

   This library is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License 
   along with this library; see the file COPYING. If not, write to the
   Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
   MA 02110-1301, USA.

   As a special exception, if you link this library with other files,
   some of which are compiled with SDCC, to produce an executable,
   this library does not by itself cause the resulting executable to
   be covered by the GNU General Public License. This exception does
   not however invalidate any other reasons why the executable file
   might be covered by the GNU General Public License.
-------------------------------------------------------------------------*/

#ifndef REG8052_H
#define REG8052_H

#include <8051.h>     /* load definitions for the 8051 core */

#ifdef REG8051_H
#undef REG8051_H
#endif

/* define 8052 specific registers only */

/* T2CON */
__sfr __at (0xC8) T2CON ;

/* RCAP2 L & H */
__sfr __at (0xCA) RCAP2L  ;
__sfr __at (0xCB) RCAP2H  ;
__sfr __at (0xCC) TL2     ;
__sfr __at (0xCD) TH2     ;

/*  IE  */
__sbit __at (0xAD) ET2    ; /* Enable timer2 interrupt */

/*  IP  */
__sbit __at (0xBD) PT2    ; /* T2 interrupt priority bit */

/* T2CON bits */
__sbit __at (0xC8) T2CON_0 ;
__sbit __at (0xC9) T2CON_1 ;
__sbit __at (0xCA) T2CON_2 ;
__sbit __at (0xCB) T2CON_3 ;
__sbit __at (0xCC) T2CON_4 ;
__sbit __at (0xCD) T2CON_5 ;
__sbit __at (0xCE) T2CON_6 ;
__sbit __at (0xCF) T2CON_7 ;

__sbit __at (0xC8) CP_RL2  ;
__sbit __at (0xC9) C_T2    ;
__sbit __at (0xCA) TR2     ;
__sbit __at (0xCB) EXEN2   ;
__sbit __at (0xCC) TCLK    ;
__sbit __at (0xCD) RCLK    ;
__sbit __at (0xCE) EXF2    ;
__sbit __at (0xCF) TF2     ;

#endif

LED程序

我们可以编写自己的LED程序了。

在任意地方创建test目录并进入,然后创建main.c文件:

main.c
#include "8052.h"

#define LED P1_0

void main()
{
    LED = 0; // or LED = 1
    while (1) {

    }
}

sdcc和keil编译器不同,所以定义的语法有些差别,在中断调用方面也有细微的差别,可以从官方文档了解具体信息。

编译

确保在test目录下:

$ sdcc main.c
$ ls
main.asm  main.ihx  main.lst  main.mem  main.rst
main.c    main.lk   main.map  main.rel  main.sym

编译完成后会生成很多文件,其中main.ihx是我们需要的。

3. 烧写程序

下载python脚本,并安装好依赖,
或者可以直接复制脚本代码。

test目录下创建stcflash.py:

#!/usr/bin/env python

# stcflash  Copyright (C) 2013  laborer (laborer@126.com)

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


import time
import logging
import sys
import serial
import os.path
import binascii
import struct
import argparse


PROTOCOL_89 = "89"
PROTOCOL_12C5A = "12c5a"
PROTOCOL_12C52 = "12c52"
PROTOCOL_12Cx052 = "12cx052"

PROTOSET_89 = [PROTOCOL_89]
PROTOSET_12 = [PROTOCOL_12C5A, PROTOCOL_12C52, PROTOCOL_12Cx052]
PROTOSET_12B = [PROTOCOL_12C52, PROTOCOL_12Cx052]
PROTOSET_PARITY = [PROTOCOL_12C5A, PROTOCOL_12C52]


class Programmer:
    def __init__(self, conn, protocol=None):
        self.conn = conn
        self.protocol = protocol

        self.conn.timeout = 0.05
        if self.protocol in PROTOSET_PARITY:
            self.conn.parity = serial.PARITY_EVEN
        else:
            self.conn.parity = serial.PARITY_NONE

        self.chkmode = 0

    def __conn_read(self, size):
        buf = bytearray()
        while len(buf) < size:
            s = bytearray(self.conn.read(size - len(buf)))
            buf += s

            logging.debug("recv: " + " ".join(["%02X" % i for i in s]))

            if len(s) == 0:
                raise IOError()

        return list(buf)

    def __conn_write(self, s):
        logging.debug("send: " + " ".join(["%02X" % i for i in s]))

        self.conn.write(bytearray(s))

    def __conn_baudrate(self, baud, flush=True):
        logging.debug("baud: %d" % baud)

        if flush:
            self.conn.flush()
            time.sleep(0.2)

        self.conn.baudrate = baud

    def __model_database(self, model):
        modelmap = {0xE0: ("12", 1, {(0x00, 0x1F): ("C54", ""),
                                     (0x60, 0x7F): ("C54", "AD"),
                                     (0x80, 0x9F): ("LE54", ""),
                                     (0xE0, 0xFF): ("LE54", "AD"),
                                     }),
                    0xE1: ("12", 1, {(0x00, 0x1F): ("C52", ""),
                                     (0x20, 0x3F): ("C52", "PWM"),
                                     (0x60, 0x7F): ("C52", "AD"),
                                     (0x80, 0x9F): ("LE52", ""),
                                     (0xA0, 0xBF): ("LE52", "PWM"),
                                     (0xE0, 0xFF): ("LE52", "AD"),
                                     }),
                    0xE2: ("11", 1, {(0x00, 0x1F): ("F", ""),
                                     (0x20, 0x3F): ("F", "E"),
                                     (0x70, 0x7F): ("F", ""),
                                     (0x80, 0x9F): ("L", ""),
                                     (0xA0, 0xBF): ("L", "E"),
                                     (0xF0, 0xFF): ("L", ""),
                                     }),
                    0xE6: ("12", 1, {(0x00, 0x1F): ("C56", ""),
                                     (0x60, 0x7F): ("C56", "AD"),
                                     (0x80, 0x9F): ("LE56", ""),
                                     (0xE0, 0xFF): ("LE56", "AD"),
                                     }),
                    0xD1: ("12", 2, {(0x20, 0x3F): ("C5A", "CCP"),
                                     (0x40, 0x5F): ("C5A", "AD"),
                                     (0x60, 0x7F): ("C5A", "S2"),
                                     (0xA0, 0xBF): ("LE5A", "CCP"),
                                     (0xC0, 0xDF): ("LE5A", "AD"),
                                     (0xE0, 0xFF): ("LE5A", "S2"),
                                     }),
                    0xD2: ("10", 1, {(0x00, 0x0F): ("F", ""),
                                     (0x60, 0x6F): ("F", "XE"),
                                     (0x70, 0x7F): ("F", "X"),
                                     (0xA0, 0xAF): ("L", ""),
                                     (0xE0, 0xEF): ("L", "XE"),
                                     (0xF0, 0xFF): ("L", "X"),
                                     }),
                    0xD3: ("11", 2, {(0x00, 0x1F): ("F", ""),
                                     (0x40, 0x5F): ("F", "X"),
                                     (0x60, 0x7F): ("F", "XE"),
                                     (0xA0, 0xBF): ("L", ""),
                                     (0xC0, 0xDF): ("L", "X"),
                                     (0xE0, 0xFF): ("L", "XE"),
                                     }),
                    0xF0: ("89", 4, {(0x00, 0x10): ("C5", "RC"),
                                     (0x20, 0x30): ("C5", "RC"),  #STC90C5xRC
                                     }),
                    0xF1: ("89", 4, {(0x00, 0x10): ("C5", "RD+"),
                                     (0x20, 0x30): ("C5", "RD+"),  #STC90C5xRD+
                                     }),
                    0xF2: ("12", 1, {(0x00, 0x0F): ("C", "052"),
                                     (0x10, 0x1F): ("C", "052AD"),
                                     (0x20, 0x2F): ("LE", "052"),
                                     (0x30, 0x3F): ("LE", "052AD"),
                                     }),
                    }

        iapmcu = ((0xD1, 0x3F), (0xD1, 0x5F), (0xD1, 0x7F),
                  (0xD2, 0x7E), (0xD2, 0xFE),
                  (0xD3, 0x5F), (0xD3, 0xDF),
                  (0xE2, 0x76), (0xE2, 0xF6),
                  )

        try:
            model = tuple(model)

            prefix, romratio, fixmap = modelmap[model[0]]

            if model[0] in (0xF0, 0xF1) and 0x20 <= model[1] <= 0x30:
                prefix = "90"

            for key, value in fixmap.items():
                if key[0] <= model[1] <= key[1]:
                    break
            else:
                raise KeyError()

            infix, postfix = value

            romsize = romratio * (model[1] - key[0])

            try:
                romsize = {(0xF0, 0x03): 13}[model]
            except KeyError:
                pass

            if model[0] in (0xF0, 0xF1):
                romfix = str(model[1] - key[0])
            elif model[0] in (0xF2,):
                romfix = str(romsize)
            else:
                romfix = "%02d" % romsize

            name = "IAP" if model in iapmcu else "STC"
            name += prefix + infix + romfix + postfix
            return (name, romsize)

        except KeyError:
            return ("Unknown %02X %02X" % model, None)

    def recv(self, timeout = 1, start = [0x46, 0xB9, 0x68]):
        timeout += time.time()

        while time.time() < timeout:
            try:
                if self.__conn_read(len(start)) == start:
                    break
            except IOError:
                continue
        else:
            logging.debug("recv(..): Timeout")
            raise IOError()

        chksum = start[-1]

        s = self.__conn_read(2)
        n = s[0] * 256 + s[1]
        if n > 64:
            logging.debug("recv(..): Incorrect packet size")
            raise IOError()
        chksum += sum(s)

        s = self.__conn_read(n - 3)
        if s[n - 4] != 0x16:
            logging.debug("recv(..): Missing terminal symbol")
            raise IOError()

        chksum += sum(s[:-(1+self.chkmode)])
        if self.chkmode > 0 and chksum & 0xFF != s[-2]:
            logging.debug("recv(..): Incorrect checksum[0]")
            raise IOError()
        elif self.chkmode > 1 and (chksum >> 8) & 0xFF != s[-3]:
            logging.debug("recv(..): Incorrect checksum[1]")
            raise IOError()

        return (s[0], s[1:-(1+self.chkmode)])

    def send(self, cmd, dat):
        buf = [0x46, 0xB9, 0x6A]

        n = 1 + 2 + 1 + len(dat) + self.chkmode + 1
        buf += [n >> 8, n & 0xFF, cmd]

        buf += dat

        chksum = sum(buf[2:])
        if self.chkmode > 1:
            buf += [(chksum >> 8) & 0xFF]
        buf += [chksum & 0xFF, 0x16]

        self.__conn_write(buf)

    def detect(self):
        for i in range(1000):
            try:
                self.__conn_write([0x7F, 0x7F])
                cmd, dat = self.recv(0.015, [0x68])
                break
            except IOError:
                pass
        else:
            raise IOError()

        self.fosc = (float(sum(dat[0:16:2]) * 256 + sum(dat[1:16:2])) / 8
                     * self.conn.baudrate / 580974)
        self.info = dat[16:]
        self.version = "%d.%d%c" % (self.info[0] >> 4,
                                    self.info[0] & 0x0F,
                                    self.info[1])
        self.model = self.info[3:5]

        self.name, self.romsize = self.__model_database(self.model)

        logging.info("Model ID: %02X %02X" % tuple(self.model))
        logging.info("Model name: %s" % self.name)
        logging.info("ROM size: %s" % self.romsize)

        if self.protocol is None:
            try:
                self.protocol = {0xF0: PROTOCOL_89,       #STC89/90C5xRC
                                 0xF1: PROTOCOL_89,       #STC89/90C5xRD+
                                 0xF2: PROTOCOL_12Cx052,  #STC12Cx052
                                 0xD1: PROTOCOL_12C5A,    #STC12C5Ax
                                 0xD2: PROTOCOL_12C5A,    #STC10Fx
                                 0xE1: PROTOCOL_12C52,    #STC12C52x
                                 0xE2: PROTOCOL_12C5A,    #STC11Fx
                                 0xE6: PROTOCOL_12C52,    #STC12C56x
                                 }[self.model[0]]
            except KeyError:
                pass

        if self.protocol in PROTOSET_PARITY:
            self.chkmode = 2
            self.conn.parity = serial.PARITY_EVEN
        else:
            self.chkmode = 1
            self.conn.parity = serial.PARITY_NONE

        if self.protocol is not None:
            del self.info[-self.chkmode:]

            logging.info("Protocol ID: %s" % self.protocol)
            logging.info("Checksum mode: %d" % self.chkmode)
            logging.info("UART Parity: %s"
                         % {serial.PARITY_NONE: "NONE",
                            serial.PARITY_EVEN: "EVEN",
                            }[self.conn.parity])

        for i in range(0, len(self.info), 16):
            logging.info("Info string [%d]: %s"
                         % (i // 16,
                            " ".join(["%02X" % j for j in self.info[i:i+16]])))

    def print_info(self):
        print(" FOSC: %.3fMHz" % self.fosc)
        print(" Model: %s (ver%s) " % (self.name, self.version))
        if self.romsize is not None:
            print(" ROM: %dKB" % self.romsize)

        if self.protocol == PROTOCOL_89:
            switches = [( 2, 0x80, "Reset stops watchdog"),
                        ( 2, 0x40, "Internal XRAM"),
                        ( 2, 0x20, "Normal ALE pin"),
                        ( 2, 0x10, "Full gain oscillator"),
                        ( 2, 0x08, "Not erase data EEPROM"),
                        ( 2, 0x04, "Download regardless of P1"),
                        ( 2, 0x01, "12T mode")]

        elif self.protocol == PROTOCOL_12C5A:
            switches = [( 6, 0x40, "Disable reset2 low level detect"),
                        ( 6, 0x01, "Reset pin not use as I/O port"),
                        ( 7, 0x80, "Disable long power-on-reset latency"),
                        ( 7, 0x40, "Oscillator high gain"),
                        ( 7, 0x02, "External system clock source"),
                        ( 8, 0x20, "WDT disable after power-on-reset"),
                        ( 8, 0x04, "WDT count in idle mode"),
                        (10, 0x02, "Not erase data EEPROM"),
                        (10, 0x01, "Download regardless of P1")]
            print(" WDT prescal: %d" % 2**((self.info[8] & 0x07) + 1))

        elif self.protocol in PROTOSET_12B:
            switches = [(8, 0x02, "Not erase data EEPROM")]

        else:
            switches = []

        for pos, bit, desc in switches:
            print(" [%c] %s" % ("X" if self.info[pos] & bit else " ", desc))

    def handshake(self):
        baud0 = self.conn.baudrate

        for baud in [115200, 57600, 38400, 28800, 19200,
                     14400, 9600, 4800, 2400, 1200]:

            t = self.fosc * 1000000 / baud / 32
            if self.protocol not in PROTOSET_89:
                t *= 2

            if abs(round(t) - t) / t > 0.03:
                continue

            if self.protocol in PROTOSET_89:
                tcfg = 0x10000 - int(t + 0.5)
            else:
                if t > 0xFF:
                    continue
                tcfg = 0xC000 + 0x100 - int(t + 0.5)

            baudstr = [tcfg >> 8,
                       tcfg & 0xFF,
                       0xFF - (tcfg >> 8),
                       min((256 - (tcfg & 0xFF)) * 2, 0xFE),
                       int(baud0 / 60)]

            logging.info("Test baudrate %d (accuracy %0.4f) using config %s"
                         % (baud,
                            abs(round(t) - t) / t,
                            " ".join(["%02X" % i for i in baudstr])))

            if self.protocol in PROTOSET_89:
                freqlist = (40, 20, 10, 5)
            else:
                freqlist = (30, 24, 20, 12, 6, 3, 2, 1)

            for twait in range(0, len(freqlist)):
                if self.fosc > freqlist[twait]:
                    break

            logging.info("Waiting time config %02X" % (0x80 + twait))

            self.send(0x8F, baudstr + [0x80 + twait])

            try:
                self.__conn_baudrate(baud)
                cmd, dat = self.recv()
                break
            except Exception:
                logging.info("Cannot use baudrate %d" % baud)

                time.sleep(0.2)
                self.conn.flushInput()
            finally:
                self.__conn_baudrate(baud0, False)

        else:
            raise IOError()

        logging.info("Change baudrate to %d" % baud)

        self.send(0x8E, baudstr)
        self.__conn_baudrate(baud)
        self.baudrate = baud

        cmd, dat = self.recv()

    def erase(self):
        if self.protocol in PROTOSET_89:
            self.send(0x84, [0x01, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33])
            cmd, dat = self.recv(10)
            assert cmd == 0x80

        else:
            self.send(0x84, ([0x00, 0x00, self.romsize * 4,
                              0x00, 0x00, self.romsize * 4]
                             + [0x00] * 12
                             + [i for i in range(0x80, 0x0D, -1)]))
            cmd, dat = self.recv(10)
            if dat:
                logging.info("Serial number: "
                             + " ".join(["%02X" % j for j in dat]))

    def flash(self, code):
        code = list(code) + [0x00] * (511 - (len(code) - 1) % 512)

        for i in range(0, len(code), 128):
            logging.info("Flash code region (%04X, %04X)" % (i, i + 127))

            addr = [0, 0, i >> 8, i & 0xFF, 0, 128]
            self.send(0x00, addr + code[i:i+128])
            cmd, dat = self.recv()
            assert dat[0] == sum(code[i:i+128]) % 256

            yield (i + 128.0) / len(code)

    def options(self, **kwargs):
        erase_eeprom = kwargs.get("erase_eeprom", None)

        dat = []
        fosc = list(bytearray(struct.pack(">I", int(self.fosc * 1000000))))

        if self.protocol == PROTOCOL_89:
            if erase_eeprom is not None:
                self.info[2] &= 0xF7
                self.info[2] |= 0x00 if erase_eeprom else 0x08
            dat = self.info[2:3] + [0xFF]*3

        elif self.protocol == PROTOCOL_12C5A:
            if erase_eeprom is not None:
                self.info[10] &= 0xFD
                self.info[10] |= 0x00 if erase_eeprom else 0x02
            dat = (self.info[6:9] + [0xFF]*5 + self.info[10:11]
                   + [0xFF]*6 + fosc)

        elif self.protocol in PROTOSET_12B:
            if erase_eeprom is not None:
                self.info[8] &= 0xFD
                self.info[8] |= 0x00 if erase_eeprom else 0x02
            dat = (self.info[6:11] + fosc + self.info[12:16] + [0xFF]*4
                   + self.info[8:9] + [0xFF]*7 + fosc + [0xFF]*3)

        elif erase_eeprom is not None:
            logging.info("Modifying options is not supported for this target")
            return False

        if dat:
            self.send(0x8D, dat)
            cmd, dat = self.recv()

        return True

    def terminate(self):
        logging.info("Send termination command")

        self.send(0x82, [])
        self.conn.flush()
        time.sleep(0.2)

    def unknown_packet_1(self):
        if self.protocol in PROTOSET_PARITY:
            logging.info("Send unknown packet (50 00 00 36 01 ...)")
            self.send(0x50, [0x00, 0x00, 0x36, 0x01] + self.model)
            cmd, dat = self.recv()
            assert cmd == 0x8F and not dat

    def unknown_packet_2(self):
        if self.protocol not in PROTOSET_PARITY:
            for i in range(5):
                logging.info("Send unknown packet (80 00 00 36 01 ...)")
                self.send(0x80, [0x00, 0x00, 0x36, 0x01] + self.model)
                cmd, dat = self.recv()
                assert cmd == 0x80 and not dat

    def unknown_packet_3(self):
        if self.protocol in PROTOSET_PARITY:
            logging.info("Send unknown packet (69 00 00 36 01 ...)")
            self.send(0x69, [0x00, 0x00, 0x36, 0x01] + self.model)
            cmd, dat = self.recv()
            assert cmd == 0x8D and not dat


def autoisp(conn, baud, magic):
    if not magic:
        return

    bak = conn.baudrate
    conn.baudrate = baud
    conn.write(bytearray(ord(i) for i in magic))
    conn.flush()
    time.sleep(0.5)
    conn.baudrate = bak


def program(prog, code, erase_eeprom=None):
    sys.stdout.write("Detecting target...")
    sys.stdout.flush()

    prog.detect()

    print(" done")

    prog.print_info()

    if prog.protocol is None:
        raise IOError("Unsupported target")

    if code is None:
        return

    prog.unknown_packet_1()

    sys.stdout.write("Baudrate: ")
    sys.stdout.flush()

    prog.handshake()

    print(prog.baudrate)

    prog.unknown_packet_2()

    sys.stdout.write("Erasing target...")
    sys.stdout.flush()

    prog.erase()

    print(" done")

    print("Size of the binary: %d" % len(code))

    # print("Programming: ", end="", flush=True)
    sys.stdout.write("Programming: ")
    sys.stdout.flush()

    oldbar = 0
    for progress in prog.flash(code):
        bar = int(progress * 20)
        sys.stdout.write("#" * (bar - oldbar))
        sys.stdout.flush()
        oldbar = bar

    print(" done")

    prog.unknown_packet_3()

    sys.stdout.write("Setting options...")
    sys.stdout.flush()

    if prog.options(erase_eeprom=erase_eeprom):
        print(" done")
    else:
        print(" failed")

    prog.terminate()


# Convert Intel HEX code to binary format
def hex2bin(code):
    buf = bytearray()
    base = 0
    line = 0

    for rec in code.splitlines():
        # Calculate the line number of the current record
        line += 1

        try:
            # bytes(...) is to support python<=2.6
            # bytearray(...) is to support python<=2.7
            n = bytearray(binascii.a2b_hex(bytes(rec[1:3])))[0]
            dat = bytearray(binascii.a2b_hex(bytes(rec[1:n*2+11])))
        except:
            raise Exception("Line %d: Invalid format" % line)

        if rec[0] != ord(":"):
            raise Exception("Line %d: Missing start code \":\"" % line)
        if sum(dat) & 0xFF != 0:
            raise Exception("Line %d: Incorrect checksum" % line)

        if dat[3] == 0:      # Data record
            addr = base + (dat[1] << 8) + dat[2]
            # Allocate memory space and fill it with 0xFF
            buf[len(buf):] = [0xFF] * (addr + n - len(buf))
            # Copy data to the buffer
            buf[addr:addr+n] = dat[4:-1]

        elif dat[3] == 1:    # EOF record
            if n != 0:
                raise Exception("Line %d: Incorrect data length" % line)

        elif dat[3] == 2:    # Extended segment address record
            if n != 2:
                raise Exception("Line %d: Incorrect data length" % line)
            base = ((dat[4] << 8) + dat[5]) << 4

        elif dat[3] == 4:    # Extended linear address record
            if n != 2:
                raise Exception("Line %d: Incorrect data length" % line)
            base = ((dat[4] << 8) + dat[5]) << 16

        else:
            raise Exception("Line %d: Unsupported record type" % line)

    return buf


def main():
    if sys.platform == "win32":
        port = "COM3"
    elif sys.platform == "darwin":
        port = "/dev/tty.usbserial"
    else:
        port = "/dev/ttyUSB0"

    parser = argparse.ArgumentParser(
        description=("Stcflash, a command line programmer for "
                     + "STC 8051 microcontroller.\n"
                     + "https://github.com/laborer/stcflash"))
    parser.add_argument("image",
                        help="code image (bin/hex)",
                        type=argparse.FileType("rb"), nargs='?')
    parser.add_argument("-p", "--port",
                        help="serial port device (default: %s)" % port,
                        default=port)
    parser.add_argument("-l", "--lowbaud",
                        help="initial baud rate (default: 2400)",
                        type=int,
                        default=2400)
    parser.add_argument("-r", "--protocol",
                        help="protocol to use for programming",
                        choices=["89", "12c5a", "12c52", "12cx052", "auto"],
                        default="auto")
    parser.add_argument("-a", "--aispbaud",
                        help="baud rate for AutoISP (default: 4800)",
                        type=int,
                        default=4800)
    parser.add_argument("-m", "--aispmagic",
                        help="magic word for AutoISP")
    parser.add_argument("-v", "--verbose",
                        help="be verbose",
                        default=0,
                        action="count")
    parser.add_argument("-e", "--erase_eeprom",
                        help=("erase data eeprom during next download"
                              +"(experimental)"),
                        action="store_true")
    parser.add_argument("-ne", "--not_erase_eeprom",
                        help=("do not erase data eeprom next download"
                              +"(experimental)"),
                        action="store_true")

    opts = parser.parse_args()

    opts.loglevel = (logging.CRITICAL,
                     logging.INFO,
                     logging.DEBUG)[min(2, opts.verbose)]

    opts.protocol = {'89': PROTOCOL_89,
                     '12c5a': PROTOCOL_12C5A,
                     '12c52': PROTOCOL_12C52,
                     '12cx052': PROTOCOL_12Cx052,
                     'auto': None}[opts.protocol]

    if not opts.erase_eeprom and not opts.not_erase_eeprom:
        opts.erase_eeprom = None

    logging.basicConfig(format=("%(levelname)s: "
                                + "[%(relativeCreated)d] "
                                + "%(message)s"),
                        level=opts.loglevel)

    if opts.image:
        code = bytearray(opts.image.read())
        opts.image.close()
        if os.path.splitext(opts.image.name)[1] in (".hex", ".ihx"):
            code = hex2bin(code)
    else:
        code = None

    print("Connect to %s at baudrate %d" % (opts.port, opts.lowbaud))

    with serial.Serial(port=opts.port,
                       baudrate=opts.lowbaud,
                       parity=serial.PARITY_NONE) as conn:
        if opts.aispmagic:
            autoisp(conn, opts.aispbaud, opts.aispmagic)
        program(Programmer(conn, opts.protocol), code, opts.erase_eeprom)


if __name__ == "__main__":
    main()

生成hex文件

$ packihx main.ihx > main.hex
packihx: read 12 lines, wrote 14: OK.
$ ls main.hex
main.hex

烧录

$ python stcflash.py main.hex

4. 多个源文件编译

不想往下写了,最后一次写51的程序,以后再也不会碰了!!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容