challis 发表于 2024-1-31 19:15:24

STC8H8K64U-软件实现串口不断电烧录程序

本帖最后由 challis 于 2024-2-1 08:45 编辑

主要原理是利用识别串口命令后进行软件复位,操作IAP_CONTR寄存器来重启芯片后从ISP区开始执行代码,来实现不断电烧录程序
完整代码在14楼

challis 发表于 2024-1-31 19:16:21

首先,利用STC工具,生成5.5296MHz,波特率为19200的串口代码
void Uart1_Isr(void) interrupt 4
{
        if (TI)                                //检测串口1发送中断
        {
                TI = 0;                        //清除串口1发送中断请求位
        }
        if (RI)                                //检测串口1接收中断
        {
                RI = 0;                        //清除串口1接收中断请求位
        }
}

void Uart1_Init(void)        //19200bps@5.5296MHz
{
        SCON = 0x50;                //8位数据,可变波特率
        AUXR &= 0xBF;                //定时器时钟12T模式
        AUXR &= 0xFE;                //串口1选择定时器1为波特率发生器
        TMOD &= 0x0F;                //设置定时器模式
        TL1 = 0xFA;                        //设置定时初始值
        TH1 = 0xFF;                        //设置定时初始值
        ET1 = 0;                        //禁止定时器中断
        TR1 = 1;                        //定时器1开始计时
        ES = 1;                                //使能串口1中断
}

challis 发表于 2024-1-31 19:27:24

构造结构体做缓存,用来缓存接收的数据
struct BUFF_DATA
{
    uchar rptr;
    uchar wptr;
    char buff;
};

challis 发表于 2024-1-31 19:29:25

定义如果5ms没有收到数据,则输出传输完成.
使用双缓冲机制,uart_buff用来缓存串口接收到的信息,str_buff用来储存一条一条的命令
新建2个BUFF_DATA的对象,并且定义一些常用操作宏
struct BUFF_DATA xdata uart_buff,xdata str_buff;

#define BUFF_POP(x) x.buff
#define BUFF_PUSH(x,d) x.buff = d
#define BUFF_HAS_DATA(x) (x.rptr != x.wptr)
#define BUFF_RESET(x) x.rptr=0;x.wptr=0

challis 发表于 2024-1-31 19:30:49

串口中断中逻辑为:如果发送完成,则将TI置0,且设置send_busy=0;
如果接收到数据,则将RI置0,且将数据存入缓存,将timeout置为5;
void Uart1_Isr(void) interrupt 4
{
        if (TI)                               
        {
                TI = 0;                       
      send_busy = 0;
        }
        if (RI)                               
        {
                RI = 0;                       
      BUFF_PUSH(uart_buff,SBUF);
      recv_timeout = 5;
        }
}

challis 发表于 2024-1-31 19:31:32

串口初始化中添加设置send_busy=0;且初始化uart_buff
void Uart1_Init(void)        //19200bps@5.5296MHz
{
        SCON = 0x50;                //8位数据,可变波特率
        AUXR &= 0xBF;                //定时器时钟12T模式
        AUXR &= 0xFE;                //串口1选择定时器1为波特率发生器
        TMOD &= 0x0F;                //设置定时器模式
        TL1 = 0xFA;                        //设置定时初始值
        TH1 = 0xFF;                        //设置定时初始值
        ET1 = 0;                        //禁止定时器中断
        TR1 = 1;                        //定时器1开始计时
        ES = 1;                                //使能串口1中断
    EA = 1;

    send_busy = 0;
    BUFF_RESET(uart_buff);
}

challis 发表于 2024-1-31 19:32:10

实现串口发送函数,发送前检测,如果send_busy,则等待
void UartSend(char dat)
{
    while(send_busy);
    send_busy = 1;
    SBUF = dat;
}

void UartSendStr(char *p)
{
    while(*p)
      UartSend(*p++);
}

challis 发表于 2024-1-31 19:34:15

主函数中循环处理,如果recv_timeout>0,则证明接收到了数据,这时,循环将串口缓存的数据取出,放入字符串缓存中,直到传输超时.传输超时则认为命令传输完成,则调用DealString函数进行处理
while(1)
    {
      if(recv_timeout>0)
      {
            BUFF_RESET(str_buff);
            while(recv_timeout>0)
            {
                while(BUFF_HAS_DATA(uart_buff))
                {
                  tmp = BUFF_POP(uart_buff);
                  BUFF_PUSH(str_buff,tmp);
                }
                recv_timeout--;
                Delay1ms();
            }
            BUFF_PUSH(str_buff,0);
            DealString(str_buff.buff);
      }
      /*if(BUFF_HAS_DATA(uart_buff))
      {
            UartSend(BUFF_POP(uart_buff));
      }*/
    }

challis 发表于 2024-1-31 19:35:18

DealString函数中,判断接收到的字符串,如果是hello,则发送world,如果是reboot,则等待2s后复位到ISP模式,其余情况则将字符串原封不动发送回去
void DealString(char *p)
{
    if(strcmp(p,"hello") == 0)
    {
      UartSendStr("world!");
    }
    else if(strcmp(p,"reboot") == 0)
    {
      Delay_ms(2000);
      IAP_CONTR = 0x60;
    }
    else
    {
      UartSendStr(p);
    }
}

challis 发表于 2024-1-31 19:37:36

烧录程序,打开STC的串口助手测试一下,发送hello,能正确收到world,发送123,能正确收到123
页: [1] 2
查看完整版本: STC8H8K64U-软件实现串口不断电烧录程序