前言
在目标开发板没有装载自动下载电路的时候,往往需要冷启动,也就是需要手动开关电源,来达到单片机复位下载。当然还有一种方法是热启动,通过串口接收到自定义的指令后,软件执行复位下载。这就是本文介绍的内容。
材料
开发板:STC8A8K64S4A12开发板(用的是STC8A8K64D4库文件来编写程序,兼容的)
因为板载有CH340C了,所以我不用外接USB-TTL。
流程
keil5步骤
-
为了快速完成串口1的配置,我使用了自己编写的串口库。该库主要实现了串口1波特率的配置,其中包括预定义波特率和单片机运行频率,初始化函数会自动计算取值。
-
在串口1的中断中编写,接收到某个指令后,执行软件复位。这里我将收到的指令设置为0x7f。
-
在主程序中调用初始化程序后,可以将主循环中的注释行取消注释,使用串口发送数据来检查串口初始化配置是否正确。在测试成功后,需要再次将该行注释掉。
完成后,编译没问题后,到下一步。
STC-ISP步骤
-
注意单片机运行频率设置。
-
配置自定义指令之类。还要注意选择下载文件。
代码
代码只有三个区块,我就在下面全部贴出来,方便验证。当然工程文件也会在文章末尾分享出来。
- main.c
- CK.c
- CK.h
-
main.c
#include <STC8A8K64D4.h> #include <CK.H> void main() { CK_Init(); while(1) { //CK_SendIntX(123); } }
-
CK.c
#include <STC8A8K64D4.h> #include <CK.H> #include <stdio.H> #include "intrins.h" //配置工作环境 #define CK_Bti 115200 //配置串口波特率 #define CK_FOSC 11059200 //单片机运行频率(默认:11.0592 (频率x10^6)) #define CK_IntStrLen 20 //整型上限个数 #define CK_FloatStrLen 20 //浮点型型上限个数(默认保留三位小数) #define CK_BRT (65536 - CK_FOSC/ CK_Bti /4) bit CK_busy; //繁忙标志 char CK_rjs; //接收缓冲计数 char CK_ryjs; //接收阅读计数 char CK_buffer[16]; //接收缓冲 int JS=0; //串口初始化 void CK_Init() { SCON=0x50; //串口1控制寄存器 //串口1工作模式_模式1:可变波特率8位数据方式 and 允许串口接收数据 TMOD=0x00; //定时器模式寄存器 //定时器/计数器1工作模式:16位自动重载模式 TL1=CK_BRT; //定时器1计数寄存器(低位) TH1=CK_BRT>>8; //定时器1计数寄存器(高位) TR1=1; //定时器T1的运行控制位 //开始计数 AUXR=0x40; //辅助寄存器1 //定时器1速度控制位_CPU时钟不分频分频(FOSC/1) ES=1; //串口1中断开关 //打开 EA=1; //中断总开关 //打开 CK_rjs=0x00; CK_ryjs=0x00; CK_busy=0; } //发送字符串 void CK_SendStr(char *p) { while(*p) { CK_SendByte(*p++); } } //发送字符串(自动换行) void CK_SendStrX(char *p) { while(*p) { CK_SendByte(*p++); } CK_SendStr("\r\n"); } //发送整型 void CK_SendInt(int num) { char str[CK_IntStrLen]; sprintf(str,"%d",num); CK_SendStr(str); } //发送整型(自动换行) void CK_SendIntX(int num) { char str[CK_IntStrLen]; sprintf(str,"%d",num); CK_SendStrX(str); } //发送浮点型 void CK_SendFloat(float num) { char str[CK_FloatStrLen]; sprintf(str,"%.3f",num); CK_SendStr(str); } //发送浮点型(自动换行) void CK_SendFloatX(float num) { char str[CK_FloatStrLen]; sprintf(str,"%.3f",num); CK_SendStrX(str); } //发送字节 void CK_SendByte(char Data) { while (CK_busy); CK_busy = 1; SBUF = Data; } //串口1中断事件 分配寄存器组1 void UartIsr() interrupt 4 using 1 { //发送 if (TI) { TI = 0; CK_busy = 0; } //接收 if (RI) { char Data; RI = 0; Data=SBUF; CK_buffer[CK_rjs++] = Data; //指令下载 if(Data==0x7f) { IAP_CONTR = 0x60; //软件复位 } // CK_rjs&=0x0f; //满16归0 //CK_SendIntX(JS++); //发送整型(自动换行) } } //电脑发送数据给单片机又发回给电脑 void CK_ReRead() { if (CK_ryjs!=CK_rjs) { CK_SendByte(CK_buffer[CK_ryjs++]); CK_ryjs &= 0x0f; } } void CK_ReadChar() { if (CK_ryjs!=CK_rjs) { CK_SendByte(CK_buffer[CK_ryjs++]); //CK_SendIntX(JS++); //发送整型(自动换行) CK_ryjs &= 0x0f; } }
-
CK.h
/* 简单串口通信库 .H文件通常用于配置 .C文件通常用于编写函数 说明:该库只是简单的应用串口1通信,和定时器1作为波特率发生器。方便调整程序。 功能:串口打印 使用说明:1.配置串口波特率,配置单片机运行频率 2.调用初始化函数 3.调用功能函数 层级:一级(为最底层无需在嵌套其他库) 标记:XY */ //基础 void CK_Init(); //串口1初始化 void CK_SendByte(char Data); //发送字节 //功能(发送) void CK_SendInt(int num); //发送整型 void CK_SendIntX(int num); //发送整型(自动换行) void CK_SendFloat(float num); //发送浮点型 void CK_SendFloatX(float num); //发送浮点型(自动换行) void CK_SendStr(char *p); //发送字符串 void CK_SendStrX(char *p); //发送字符串(自动换行) void CK_ReRead(); //电脑发送数据给单片机又发回给电脑 //功能(接收) void CK_ReadChar();
最后
本文仅介绍了利用串口进行简单热启动下载的方法。在实际的工程中,可能需要增加多字节识别等逻辑以增强稳定性,防止误判断等情况的发生。当然,这些只是一种思路,读者可以根据具体需求进行适当修改。
链接:https://pan.baidu.com/s/1RXhOqAoJR-sZZc3Q4fbd8Q 提取码:lbs9