通过第三方程序实现对STC单片机的程序下载,可以方便进行现场的调试和更新。特别是对于设计远程程序更新、无线程序下载与调试等功能有帮助。
本文给出了下载相关的一些程序设计。
在手边并没有成文的对STC单片机ISP下载协议,仅仅在STC官方网站
的STC8G,8H,8A单片机手册中给出了“使用第三方MCU对STC8G,8H, 8A”系列的但潘辰进行ISP下载的范例程序。参考这些程序,可以完成对STC8G系列的单片机内部的FLASH程序的更新。
▲ STC8G技术手册中的下载协议
对于STC单片机内部的“硬件选项”,手册建议还是使用官方的原来的STC-ISP下载程序完成配置,这比较可靠。
▲ STC单片机的硬件选项
下面给出了使用STC8G1K17单片机中,C语言实现的ISP程序。
下面给出单片机借助的外部资源以及相应的源码。
程序使用了STC8G1k的UART2完成对下载MCU发送相关的指令。需要注意的是,在ISP通信过程UART2需要设置为9bit的工作模式,这在开始的我并没有注意,造成前期的调试受阻。
为了避免串口线对被调试单片机反向供电,特别是在外部单片机掉电进行冷启动的过程中,由于串口的电压可能仍然能够满足被下载单片机的工作电源需要,通过对UART2对应的输出管脚置为高阻状态来避免反向供电。这一点,并没有像STC8G1K08手册中推荐的使用电阻和二极管来进行电源个的的方案。
▲ STC单片机数据手册中推荐的串口电源隔离方案
使用了STC8G1K08的CCP2产生PWM波形来整流出高压( 2 V C ≈ 2 × 5 V ≈ 10 V 2V_C \approx 2 \times 5V \approx 10V 2VC≈2×5V≈10V)来驱动MOS管。详细的方案可以参见博文如何利用单片机IO口产生两倍的电源电压
中的描述。
在对被下载单片机电源控制的同时,也需要改变UART2的RXD,TXD管脚的输出状态。在关闭电源的时候,将RXD,TXD设置为INPUT的高阻模式,可以避免对ISP单片机端口供电。下面代码显示了这里的控制。
//------------------------------------------------------------------------------
void ispPowerOn(void) {
P10V_ON;
PM_BIDIR(RXD2_PIN);
PM_PP(TXD2_PIN);
}
void ispPowerOff(void) {
PM_INPUT(RXD2_PIN);
PM_INPUT(TXD2_PIN);
P10V_OFF;
}
程序的其它部分可以参见数据手册中的范例程序进行阅读。由于没有正式的问题,在这里也就不再对下载的协议反向解释了。
程序的头文件。
/*
**==============================================================================
** STCISP.H: -- by Dr. ZhuoQing, 2020-04-30
**
** Description:
**
**==============================================================================
*/
#ifndef __STCISP__
#define __STCISP__
//------------------------------------------------------------------------------
#ifdef STCISP_GLOBALS
#define STCISP_EXT
#else
#define STCISP_EXT extern
#endif // STCISP_GLOBALS
//------------------------------------------------------------------------------
//==============================================================================
#define PWM_PIN 3, 7
#define P5V_PIN 3, 6
#define RXD2_PIN 1, 0
#define TXD2_PIN 1, 1
//------------------------------------------------------------------------------
#define P10V_ON ON(P5V_PIN), PWM3SetPWM(0x7f)
#define P10V_OFF OFF(P5V_PIN), PWM3SetPWM(0xff)
//------------------------------------------------------------------------------
void ispInit(unsigned long lnBaud);
void ispPowerOn(void);
void ispPowerOff(void);
#define ISP_POWEROFF_TIME 200 // unit :ms
STCISP_EXT unsigned int g_nIspPowerOffTime;
void ispSetBaud(unsigned long lnBaud, unsigned char uc9BitFlag);
// uc9BitFlag: 1 : Set UART2 as 9bit mode
// 0 : as 8 bit mode
//------------------------------------------------------------------------------
STCISP_EXT unsigned int g_nispReceiveSum;
STCISP_EXT unsigned char g_ucispReceiveIndex, g_ucispReceiveCount, g_ucispReceiveStep;
STCISP_EXT unsigned char xdata g_ucispRxBuffer[64], g_ucispTxBuffer[150];
STCISP_EXT unsigned char g_ucispReceiveFlag;
//------------------------------------------------------------------------------
STCISP_EXT unsigned int g_nispProgramStart;
STCISP_EXT unsigned char g_ucispProgramLength;
#define ISP_PROGRAM_BUFFER 256
STCISP_EXT unsigned char xdata g_ucispProgramBuffer[ISP_PROGRAM_BUFFER];
//------------------------------------------------------------------------------
void ispProcChar(void);
void ispCommunicationInit(void);
unsigned char ispSendChar(unsigned char ucChar);
void ispCommandSend(unsigned char ucSize);
void ispRun(unsigned long lnBaud, unsigned int nTime);
//------------------------------------------------------------------------------
void ispShowRxBuffer(void);
//------------------------------------------------------------------------------
#define FALSE 1
#define TRUE 0
typedef bit BOOL;
typedef unsigned char BYTE;
typedef unsigned short WORD;
#define LOBYTE(w) ((BYTE)(WORD)(w))
#define HIBYTE(w) ((BYTE)((WORD)(w) >> 8))
#define FUSER 35000000L
#define RL(n) (0x10000 - FUSER/4/(n))
#define ISP_DOWNLOAD_CHECKLOOP 100
#define ISP_DOWNLOAD_BAUD 115200L
#define ISP_DOWNLOAD_TIMEOUT 2000
#define ISP_DOWNLOAD_TIMEOUT_ERASE 2000
#define ISP_DOWNLOAD_PAGESIZE 128
//------------------------------------------------------------------------------
#define ISP_ARG7_8H 0x97
#define ISP_ARG7_8G 0x97
#define ISP_ARG7_8A 0x81
unsigned char ispEnterISP(unsigned long lnStartBaud, unsigned long lnBaud,
unsigned char ucArg7, unsigned long lnFosc);
unsigned char ispEraseMCU(void);
unsigned char ispDownloadCode(unsigned char * pucCode, unsigned int nSize,
unsigned int nStartAddress);
//------------------------------------------------------------------------------
//==============================================================================
// END OF THE FILE : STCISP.H
//------------------------------------------------------------------------------
#endif // __STCISP__
程序的C语言文件。
/*
**==============================================================================
** STCISP.C: -- by Dr. ZhuoQing, 2020-04-30
**
**==============================================================================
*/
//------------------------------------------------------------------------------
#define STCISP_GLOBALS 1 // Define the global variables
#include "STCISP.H"
#include "STC8G.H"
#include "C51BASIC.H"
#include
//------------------------------------------------------------------------------
void ispInit(unsigned long lnBaud) {
//--------------------------------------------------------------------------
ispSetBaud(lnBaud, 0);
//--------------------------------------------------------------------------
ispCommunicationInit();
//--------------------------------------------------------------------------
PM_PP(PWM_PIN);
PM_PP(P5V_PIN);
P10V_ON;
g_nIspPowerOffTime = ISP_POWEROFF_TIME;
}
//------------------------------------------------------------------------------
void ispRun(unsigned long lnBaud, unsigned int nTime) {
ispPowerOff();
WaitTime(nTime);
ispPowerOn();
ispSetBaud(lnBaud, 0);
UART2_CLEAR;
}
//------------------------------------------------------------------------------
void ispPowerOn(void) {
P10V_ON;
PM_BIDIR(RXD2_PIN);
PM_PP(TXD2_PIN);
}
void ispPowerOff(void) {
PM_INPUT(RXD2_PIN);
PM_INPUT(TXD2_PIN);
P10V_OFF;
}
void ispSetBaud(unsigned long lnBaud, unsigned char uc9BitFlag) {
unsigned int nNumber;
nNumber = Baud2TimeReload(lnBaud, 35000000L);
if(uc9BitFlag)
S2CON |= 0x80; // Enable bit9 communication
else S2CON &= ~0x80;
T2H = nNumber >> 8;
T2L = nNumber;
}
void ispCommunicationInit(void) {
unsigned int i;
for(i = 0; i < sizeof(g_ucispRxBuffer); i ++)
g_ucispRxBuffer[i] = 0;
g_nispReceiveSum = 0;
g_ucispReceiveIndex = g_ucispReceiveCount = g_ucispReceiveStep = 0;
g_ucispReceiveFlag = 0;
}
//------------------------------------------------------------------------------
void ispProcChar(void) {
unsigned char ucChar;
if(!UART2_CANRECE) return;
UART2ReceChar(&ucChar);
//--------------------------------------------------------------------------
// printf("%bx ", ucChar);
//------------------------------------------------------------------------
switch(g_ucispReceiveStep) {
case 1:
if(ucChar != 0xb9) goto L_CheckFirst;
g_ucispReceiveStep ++;
break;
case 2:
if(ucChar != 0x68) goto L_CheckFirst;
g_ucispReceiveStep ++;
break;
case 3:
if(ucChar != 0x0) goto L_CheckFirst;
g_ucispReceiveStep ++;
break;
case 4:
g_nispReceiveSum = 0x68 + ucChar;
g_ucispReceiveCount = ucChar - 6;
g_ucispReceiveIndex = 0;
g_ucispReceiveStep ++;
break;
case 5:
g_nispReceiveSum += ucChar;
g_ucispRxBuffer[g_ucispReceiveIndex ++] = ucChar;
if(g_ucispReceiveIndex == g_ucispReceiveCount)
g_ucispReceiveStep ++;
break;
case 6:
if(ucChar != (unsigned char)(g_nispReceiveSum >> 8))
goto L_CheckFirst;
g_ucispReceiveStep ++;
break;
case 7:
if(ucChar != (unsigned char)(g_nispReceiveSum & 0xff))
goto L_CheckFirst;
g_ucispReceiveStep ++;
break;
case 8:
if(ucChar != 0x16) goto L_CheckFirst;
g_ucispReceiveFlag = 1;
g_ucispReceiveStep ++;
break;
L_CheckFirst:
case 0:
default:
ispCommunicationInit();
if(ucChar == 0x46) g_ucispReceiveStep = 1;
else g_ucispReceiveStep = 0;
break;
}
}
//------------------------------------------------------------------------------
/*
void ispShowRxBuffer(void) {
unsigned int i;
printf("Count:%bd\r\n", g_ucispReceiveCount);
for(i = 0; i < g_ucispReceiveCount; i ++)
printf("%bx ", g_ucispRxBuffer[i]);
printf("\r\n");
}
*/
//------------------------------------------------------------------------------
unsigned char ispSendChar(unsigned char ucChar) {
g_ucUART2IntFlag = 0;
ACC = ucChar;
S2CON &= ~0x8;
if(P) S2CON |= 0x8;
S2BUF = ACC;
while(1) {
if(g_ucUART2IntFlag) break;
}
return ucChar;
}
//------------------------------------------------------------------------------
void ispCommandSend(unsigned char ucSize) {
unsigned int nSum;
unsigned char i, c;
ispSendChar(0x46);
ispSendChar(0xb9);
ispSendChar(0x6a);
ispSendChar(0x00);
nSum = ucSize + 6 + 0x6a;
ispSendChar(ucSize + 6);
for(i = 0; i < ucSize; i ++) {
c = g_ucispTxBuffer[i];
nSum += c;
ispSendChar(c);
}
ispSendChar((unsigned char)(nSum >> 8));
ispSendChar((unsigned char)(nSum & 0xff));
ispSendChar(0x16);
ispCommunicationInit();
}
//------------------------------------------------------------------------------
unsigned char ispEnterISP(unsigned long lnStartBaud, unsigned long lnBaud,
unsigned char ucArg7, unsigned long lnFosc) {
unsigned char ucArg;
unsigned int nCheckLoop;
unsigned int nMS10;
unsigned int nBaudTimeReload;
//----------------------------------------------------------------------
ispCommunicationInit();
ispSetBaud(lnStartBaud, 1);
// printf("Set baud:%ld\r\n", lnStartBaud);
//--------------------------------------------------------------------------
ispPowerOff();
WaitTime(g_nIspPowerOffTime);
ispPowerOn();
nMS10 = (unsigned int)(GetClickMS() + 10);
nCheckLoop = 0;
for(nCheckLoop = 0; nCheckLoop < ISP_DOWNLOAD_CHECKLOOP;) {
ispProcChar();
if(g_ucispReceiveStep == 0) {
if(GetClickMS() == nMS10) {
ispSendChar(0x7f);
nMS10 = (unsigned int)(GetClickMS() + 10);
nCheckLoop ++;
}
}
if(g_ucispReceiveFlag) {
ucArg = g_ucispRxBuffer[4];
if(g_ucispRxBuffer[0] == 0x50)
break;
return 1; // return error
}
}
if(nCheckLoop >= ISP_DOWNLOAD_CHECKLOOP) return 2;
//--------------------------------------------------------------------------
// Set new baud
// printf("\r\nSet new Buad:%ld/%d\r\n", lnBaud, nCheckLoop);
nBaudTimeReload = Baud2TimeReload(lnBaud, lnFosc);
// printf("%x\r\n", nBaudTimeReload);
ucArg = g_ucispRxBuffer[4];
g_ucispTxBuffer[0] = 0x01;
g_ucispTxBuffer[1] = ucArg;
g_ucispTxBuffer[2] = 0x40;
g_ucispTxBuffer[3] = HIBYTE(nBaudTimeReload);
g_ucispTxBuffer[4] = LOBYTE(nBaudTimeReload);
g_ucispTxBuffer[5] = 0x00;
g_ucispTxBuffer[6] = 0x00;
g_ucispTxBuffer[7] = ucArg7;//0x97;//0x81;//0x97; // 0x81: STC8A
// 0x97: STC8G,8H
nMS10 = (unsigned int)(GetClickMS() + ISP_DOWNLOAD_TIMEOUT);
ispCommandSend(8);
for(;;) {
ispProcChar();
if(g_ucispReceiveFlag) {
if(g_ucispRxBuffer[0] == 0x01) break;
return 3;
}
if(GetClickMS() == nMS10) return 4;
}
//----------------------------------------------------------------------
// Prepare the new download baud
ispSetBaud(lnBaud, 1);
// WaitTime(10);
g_ucispTxBuffer[0] = 0x05;
g_ucispTxBuffer[1] = 0x00;
g_ucispTxBuffer[2] = 0x00;
g_ucispTxBuffer[3] = 0x5a;
g_ucispTxBuffer[4] = 0xa5;
nMS10 = (unsigned int)(GetClickMS() + ISP_DOWNLOAD_TIMEOUT);
ispCommandSend(5);
for(;;) {
ispProcChar();
if(g_ucispReceiveFlag) {
if(g_ucispRxBuffer[0] == 0x05) break;
return 5;
}
if(GetClickMS() == nMS10) return 6;
}
return 0;
}
//------------------------------------------------------------------------------
unsigned char ispEraseMCU(void) {
unsigned int nMS10;
//----------------------------------------------------------------------
// Erase the IC
WaitTime(10);
g_ucispTxBuffer[0] = 0x03;
g_ucispTxBuffer[1] = 0x00;
g_ucispTxBuffer[2] = 0x00;
g_ucispTxBuffer[3] = 0x5a;
g_ucispTxBuffer[4] = 0xa5;
nMS10 = (unsigned int)(GetClickMS() + ISP_DOWNLOAD_TIMEOUT_ERASE);
ispCommandSend(5);
for(;;) {
ispProcChar();
if(g_ucispReceiveFlag) {
if(g_ucispRxBuffer[0] == 0x03) break;
return 1;
}
if(GetClickMS() == nMS10) return 2;
}
return 0; // OK
}
//------------------------------------------------------------------------------s
unsigned char ispDownloadCode(unsigned char * pucCode, unsigned int nSize, unsigned int nStartAddress) {
unsigned int i, nStep, nLength, j;
unsigned int nDownloadAddress, nStart, nEnd, nOffset;
unsigned int nPoint;
unsigned int nMS10;
nStep = (int)((nSize + ISP_DOWNLOAD_PAGESIZE - 1) / ISP_DOWNLOAD_PAGESIZE);
g_ucispTxBuffer[0] = 0x22;
g_ucispTxBuffer[3] = 0x5a;
g_ucispTxBuffer[4] = 0xa5;
nOffset = 5;
nPoint = 0;
for(i = 0; i < nStep; i ++) {
nStart = i * ISP_DOWNLOAD_PAGESIZE;
nEnd = nStart + ISP_DOWNLOAD_PAGESIZE;
if(nEnd > nSize) nEnd = nSize;
nLength = nEnd - nStart;
nDownloadAddress = nStartAddress + nStart;
g_ucispTxBuffer[1] = HIBYTE(nDownloadAddress);
g_ucispTxBuffer[2] = LOBYTE(nDownloadAddress);
for(j = 0; j < nLength; j ++) {
g_ucispTxBuffer[nOffset + j] = *(pucCode + nPoint);
nPoint ++;
}
nMS10 = (unsigned int)(GetClickMS() + ISP_DOWNLOAD_TIMEOUT);
ispCommandSend(nLength + nOffset);
for(;;) {
ispProcChar();
if(g_ucispReceiveFlag) {
if(g_ucispRxBuffer[0] == 0x2 &&
g_ucispRxBuffer[1] == 'T') break;
return 1;
}
if(GetClickMS() == nMS10) return 2;
}
g_ucispTxBuffer[0] = 0x02;
}
return 0;
}
//==============================================================================
// END OF THE FILE : STCISP.C
//------------------------------------------------------------------------------