Harbin Institute of Technology Amateur Radio Club

STC单片机程序下载原理和自动下载

==

作者:王浩宇 Qrpucp

目录

一.stc单片机下载程序的原理

在stc单片机中有两个程序区:用户程序区和ISP监控程序区。

这是STC89C52单片机数据手册中的内容。

复位源

根据数据手册,我们可以知道,当冷启动或者对ISP_CONTR寄存器送入60H(STC12、15、8是对IAP_CONTR寄存器送入60H)产生复位以后,单片机会从ISP监控程序区开始执行程序。(高系列的STC有更多方式可以进入ISP监控程序区)

如果在这时候没有检测到合法的ISP下载命令流,单片机就会从ISP程序监控区软复位到用户程序区开始执行程序。

如果检测到合法的ISP下载命令流,则单片机开始与ISP下载软件通信(如stc-isp),单片机会以相同的波特率回复给下载软件50个数据,这也就是为什么我们可以从软件中看到我们单片机当前的设置。

返回数据

单片机随后擦除flash程序存储器,与此同时软件也会进入编程模式,以最高波特率向单片机发送程序码,单片机接收程序码,并将其写入flash程序存储器中。成功后,用户程序立即生效,开始运行用户程序。

那什么是合法的ISP下载命令流呢?

ISP下载命令流

从图上可以看到,当我们按下“下载/编程”后,电脑会通过串口给单片机发送一系列数据。

如果我们在stc-isp上勾选了发送自定义命令的话,stc-isp首先会按照我们设置的波特率、停止位等配置向单片机发送我们自定义的命令。

然后stc-isp会以我们设置的最低波特率和默认配置每隔约12ms向单片机发送一次0x7F,这通常就是我们所说的“合法的ISP下载命令流”。

简单的话概括就是:当我们点击stc-isp软件上的下载按钮后,软件会向单片机发送ISP下载命令流,单片机在ISP程序监控区接收到合法的ISP下载命令流之后,会向软件回复自身信息,擦除原flash区域,写入新的程序并开始执行。

非常简单且不严谨的话概括就是:单击stc-isp的下载按钮后,stc单片机进行一次复位,便可以下载程序。

二.冷启动下载

我们刚开始接触stc单片机一般采用的都是冷启动来下载程序,但是这样做有一定的缺点。

首先,一些特殊的外围电路要求一直保持有电状态,其次多次按压自锁开关也比较麻烦。

最后,也是我主要想说的一点是,市面上的USB转TTL模块质量参差不齐,绝大多数模块都没有做好隔离,导致电流会从模块的TX和RX倒灌进单片机,如果此时单片机上的电压高于单片机的上电复位检测门槛电压的话,就会导致单片机无法冷启动,进而无法成功下载程序。

冷启动复位

STC15单片机的数据手册中对上电复位检测门槛电压做了解释,我们可以看到,5V单片机冷启动需要把电压降至3.2V以下,3.3V单片机冷启动需要把电压降至1.8V以下。

作者测量了市面上购买的两款USB转TTL模块(PL2303),一款模块会从TX和RX给单片机提供3.3V电压,这时候5V单片机的冷启动就很可能失败。另一款模块会给单片机提供2V电压,可见这两款USB转TTL模块都是无法正常给3.3V单片机烧录程序的。

正规的单片机开发板上下载电路的隔离一般是做的非常好的,我用来测试的是郭天祥的TX-1C开发板,在不接VCC的情况下,USB只能给单片机提供0.02V的电压。

STC数据手册中给我们提供了一个简单的PL2303下载电路,其中红色箭头指向的那个电阻和二极管就是起隔离作用的。有些人可能会对那个二极管产生疑惑:反向不导通还怎么进行通讯?这就是另外一个问题了,大家可以自行从网上查阅资料。

隔离电路

当然,如果对隔离要求更为严格的话,还是要去查看USB芯片(如PL2303,CH340,FT232等)的数据手册,设计最为合适的下载电路。

三.自动下载程序

正是因为冷启动下载程序的种种弊端,催生了很多种类型的“自动下载”。说是自动下载,可不是程序会自动跑到你的单片机里,它指的是当我们按下下载这个按钮时,程序就会直接下载到单片机中。

我们也可以在stc-isp软件中设置,当我们的程序修改编译以后就自动下载进单片机。

自动下载

我们再回忆一下stc单片机下载程序需要什么。第一是需要程序从ISP监控程序区开始运行,第二是需要检测到合法的ISP下载命令流。ISP下载命令流是我们点击下载时,stc-isp提供给我们的,所以我们只需要让单片机在检测到合法的下载命令流以后,进入到ISP程序监控区,便可以实现自动下载了。

随着STC版本的提高,产生复位的方法越来越多,自动下载的方法也就随之越来越多,这里我给所有自动下载的方法简单地分为三类。

1.硬件自动下载

所谓硬件自动下载,就是完全在硬件电路上进行操作,不需要对单片机内部的程序进行修改。

市面上大概有两种硬件自动下载的方法,一种是拿另一块单片机(通常为SOP8封装)通过软件检测ISP下载命令流,如果检测到就给主单片机断开供电再恢复,实现主单片机的冷启动复位。另一种是检测通讯芯片上的联络输出信号引脚在下载程序时的电平变化,进而实现单片机的自动冷启动。

这两种方法各有利弊,利用另一块单片机来检测,成本高、操作麻烦(需要给控制下载的单片机烧录程序),但是却胜在稳定。利用通讯芯片来检测,成本低,但有时候会出bug。而且硬件的这两种方法有个共同的毛病,就是单片机还是要冷启动,无法满足单片机和外设不断电的要求。

首先简单说一下第一种方法,如果使用的是STC15W10x系列的单片机的话,它是没有硬件串口的,需要我们自己模拟串口,如果用STC8F1K08S2的SOP8封装则没有这个问题。然后由于不需要考虑资源占用问题,我们可以加入自适应波特率的代码,实现多个波特率下的自动下载。这种方法虽然刚开始设计硬件和写代码麻烦一些,但是一旦成功便非常方便。

下面详细地说一下第二种方法。

以CH340C芯片为例,联络输出信号引脚为RTS和DTR。作者用逻辑分析仪抓了一下stc-isp在串口通讯和下载程序时这两个引脚电平的变化。

时序1

上图是最低波特率2400,最高波特率115200,逻辑分析仪采样频率为100MHz时的数据。从图中可以看出来,当单片机接收到下载信号时,RTS和DTR同步拉低,当下载完毕后RTS和DTR同步拉高,低电平的时间约为4.7s。

经多次测试,单片机下载程序所用时间与我们设置的最低波特率和最高波特率有关密切相关,波特率越高,下载时间就越短,这和我们前面说的下载原理相符。

用stc-isp进行串口通讯时,打开串口时RTS和DTR拉低,关闭串口时RTS和DTR拉高。

所以这种方式的自动下载就是检测DTR或者RTS引脚在程序下载时的下降沿,然后进行一段时间的断电。下面是作者在网络上找的一个自动下载电路,断电时间约为0.5秒。

自动下载电路

有几点说明:

  1. 作者使用的是CH340C芯片,用stc-isp下载时DTR和RTS只会拉低一次。作者看到网上有人说用CH340G芯片下载时,DTR和RTS会输出连续好几个脉冲,但作者并没有验证。

  2. 用不同的上位机进行串口通讯时,DTR和RTS输出的信号是不一样的,上面的测试仅限于stc-isp。事实上作者也用安信可串口调试助手和正点原子的串口调试助手做了测试,这两个串口调试助手在串口通信时的时序图如下。而且需要说明的是,只有第一次打开串口会出现下面的时序,而且如果使用这两款串口调试助手通讯过,再使用stc-isp下载程序,DTR和RTS的电平就不会再发生变化,一直为高电平。

时序2

2.软件自动下载

软件自动下载的原理是在单片机中检测ISP下载命令流,检测到以后就给单片机一个复位信号实现软件复位并下载程序。

这种方法可以不断电实现程序的下载,而且几乎不占用单片机的资源,但是需要提前给单片机中加入自动下载的代码才可以实现自动下载,每次打开stc-isp时还需要手动设置最低波特率。

下面给出一个STC89C52的代码参考,具体配置可以查看注释,其余STC系列的单片机只需要对寄存器稍作修改就可以使用。

首先是serve.c中的代码:

//配置串口
void uart_init(void)
{
    TMOD = 0x20;    
    TH1 = 0xfd;     
    TL1 = 0xfd;     
    TR1 = 1;       
    REN = 1;       
    SM0 = 0;      
    SM1 = 1;       
    EA = 1;         					
    ES = 1;        
}

serve.h:

/*
funtion:automatic download
explanation:			
    switch:#define _DOWNLOAD_(before #include"serve.h")
    remember to use uart_init before!				
*/
					
#ifdef _DOWNLOAD_
					
#include<reg52.h>

sfr ISP_CONTR = 0xe7;

void uart1_ser() interrupt 4
{ 
    static uint8_t uart_ser_n = 0;
    RI = 0;        //清空接收标志位
    if(SBUF == 0x7f)  //STC下载指令0X7F
    { 	
        uart_ser_n++;   //判断位自加
        if(uart_ser_n == 10) //如果收到10次0X7F
        {
            uart_ser_n = 0;   //判断位清0
            ISP_CONTR = 0x60;//复位命令  
        }
    
    else
    {
        uart_ser_n = 0;	
    }
}
				


#endif

/*
explanation:
    crystal frequency:11.0592MHz
    bps:9600
    timer1:mode2
    UART:mode1
*/

extern void uart_init(void);

下面是main.c中的一个小示例:

#define _DOWNLOAD_
#include "serve.h"
#include <reg52.h>

int main()
{
    uart_init();
    while(1)
    {
        P1 = ~P1;
        delay_ms(100);
    }
}

这里作者并没有选择使用stc-isp上的发送自定义命令,因为不管发送不发送自定义命令,stc-isp最后总是要不断发送0x7F的ISP下载流,作者偷了个懒,就没有配置自定义命令,这样别人拿过我的单片机也可以直接自动下载了。

可能有人会问:既然总是要发送0x7F的ISP下载流,那为什么stc-isp还要设置”发送自定义命令“这样一个功能呢?

那是因为在发送自定义命令时我们可以自主选择串口通信的波特率、校验位、停止位等参数,且可以自主设置命令,这样就使得自动下载这个功能非常灵活,在比较复杂的项目里面使用自主设置命令会更加合适。

3.外部触发自动下载

除了上面说的自动下载的方法,其实还有很多自动下载的方法,它们都可以归到这一类,比如复位按键、外部中断等等。他们对单片机资源占用各不相同,复杂程度也各不相同,这里就不展开说了,大家可以自行探索。事实上现在很多STC高系列的开发板都是通过复位按键来下载程序的。

参考资料:

  1. https://www.bilibili.com/read/cv4246862
  2. http://mouser.eetrend.com/content/2017/100005986.html