本帖最后由 逍遥派掌门 于 2015-11-26 23:57 编辑
STC单片机的串口下载无疑是非常方便的,既节省了专用下载器的花费,又不占用资源,这点秒杀AVR单片机。
但它有一个稍麻烦的地方:每次下载前需要对单片机进行手动复位。
我们利用STC提供的寄存器ISP_CONTR (有的型号是 IAP_CONTR,这个寄存器的定义要参看具体的datasheet)搞点花样,把手动的复位变成自动的复位。
这个只要在单片机的软件上增加一定的代码就可以实现了,不用改动任何的硬件,安全可靠哦。
先上Turbo51的代码:
Program main;
{$IDATA} { 申请使用IDATA}
Const
{与STC12C5604AD有关}
SWBS = $40;
SWRST = $20;
BaudRate = 9600; {通信用的波特率}
oscll = 11059200; {晶振频率}
BaudRateTimerValue = Byte (- oscll div 12 div 32 div BaudRate);
Header = $7E; {起始字}
Address = $01; {单片机地址}
TX_Length_limit = 10 ; {按照协议,发送的字节数}
RX_Length_limit = 10 ; {按照协议,接收的字节数}
RX_min = 3 ;
command_list_0 = $00; { 程序下载}
command_list_1 = $01;
type
TSerialRecord = Record
RX_Buffer: Array [1..RX_Length_limit] of Byte; { 接收缓冲区,一个字节的字模 + 规定的字节}
RX_Count : byte; { 接收到的数量}
RX_Sum : byte; { 接收校验}
TX_Buffer: Array [1..TX_Length_limit] of byte; { 发送缓冲区}
TX_Number: byte; { 需要发送的总数量}
TX_Sum : byte; { 发送校验和}
TX_Count : byte; { 发送的计数}
TX_Length: byte; {发送的长度限制}
RX_Length: byte; { 接收的长度限制}
RX_finish : byteBool;
TX_finish : byteBool;
TX_need : byteBool;
end;
var
serial_0: TSerialRecord IDATA;
{与STC12C5604AD有关}
P2M0 : byte absolute $95;Volatile;
P2M1 : byte absolute $96;Volatile;
P3M0 : byte absolute $B1;Volatile;
P3M1 : byte absolute $B2;Volatile;
AUXR : byte absolute $8E;Volatile;
ISP_CONTR : byte absolute $E7;Volatile;
{************************************************************************}
{接收处理}
Procedure Do_receive;
var
number : byte;
begin
with serial_0 do
begin
if (RX_finish = True) then
begin
RX_Sum := 0;
for number := 1 to (RX_Count-1) do RX_Sum:= RX_Sum + RX_Buffer[number];
if (RX_Sum = RX_Buffer[RX_Length]) then
begin
case RX_Buffer[3] of {判断命令}
command_list_0:
begin
ISP_CONTR := SWBS or SWRST ; {关键!将复位指令送到寄存器 ISP_CONTR}
end;
command_list_1:
begin
end;
command_list_2:
begin
end;
command_error:
begin
end;
end;
TX_Buffer[3] := RX_buffer[3];
TX_Number := RX_Count;
TX_need := True; {发送应答}
end;
RX_Count := 1;
RX_finish := False;
end;
end;
end;
{************************************************************************}
{发送处理}
Procedure Do_send;
var
number : byte;
begin
with serial_0 do
begin
if (TX_need = True) and (TX_finish = True) then
begin
TX_Sum := 0;
for number := 1 to (TX_Number -1) do TX_Sum := TX_Sum + TX_Buffer[number];
TX_Buffer[TX_Number] := TX_Sum;
TX_Count := 1;
TX_finish := False;
TX_need := False ;
TI := True; {开启发送}
end;
end;
end;
{************************************************************************}
{串行中断}
Procedure RS232; Interrupt Serial;
begin
with serial_0 do
begin
If (RI = True) then {接收中断}
begin
RI := False;
if (RX_finish = False) then
begin
RX_Buffer[RX_Count] := SBUF; {接收字节}
inc(RX_Count);
if (RX_Count > RX_min) then
begin
if ((RX_Buffer[1]= Header) and (RX_Buffer[2]= Address)) then
begin
if (RX_Count > (3 + RX_Buffer[3] + 2)) then
begin
RX_finish := True;
end
end
else begin
RX_Count :=1;
end;
end;
end;
end;
If (TI =True) then {发送中断}
begin
TI := False;
if TX_Count < (TX_Number + 1) then {判断是否已经发送完毕}
begin
SBUF := TX_Buffer[TX_Count]; {发送字节}
Inc (TX_Count);
end
else TX_finish := True;
end;
end;
end;
{************************************************************************}
{初始化}
procedure init;
begin
with serial_0 do
begin
TX_Buffer[1] := HEADER;
TX_Buffer[2] := ADDRESS;
TX_Length := TX_Length_limit;
RX_Length := RX_Length_limit;
TX_Sum := 0;
RX_Sum := 0;
RX_Count :=1;
RX_finish := False;
TX_finish := True;
TX_need := False;
end;
P2M0 := $00;
P2M1 := $00;
P3M0 := $FF;
P3M1 := $FF;
PCON := PCON and $7f;
SCON := $50;
AUXR := AUXR and $bf;
AUXR := AUXR and $fe;
TMOD := TMOD and $0f;
TMOD := TMOD or $20;
TL1 := BaudRateTimerValue;
TH1 := BaudRateTimerValue;
ET1 := False;
TR1 := True;
ES :=True;
EA :=True;
end;
{************************************************************************}
{主程序}
begin
init;
Repeat
Do_receive;
Do_send;
until False;
end.
上面的代码,是通过串口接收指定的协议串,然后改变单片机特殊寄存器的值,从而达到复位单片机的目的。
通讯协议部分稍微复杂,主要的核心是第71行的代码。
同时要在STC的下载软件里做如下(红色框)的设置:
这样,你就不用再每次手动复位单片机,只需要第一次下载本程序时,手动复位一下,以后就可以专注于代码的编写。
完整代码文件:
stc_isp.rar
(1.68 KB)
|