OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 6253|回复: 4

关于单片机ISP在线升级程序的一些疑问,希望大神能帮下忙

[复制链接]

19

主题

64

帖子

0

精华

初级会员

Rank: 2

积分
160
金钱
160
注册时间
2014-5-23
在线时间
0 小时
发表于 2014-8-5 11:33:21 | 显示全部楼层 |阅读模式
5金钱
这是在线升级程序
/*------------------------------------------------------------------*/
/* --- STC MCU International Limited -------------------------------*/
/* --- STC IAP 系列单片机实现用户ISP 演示程序 ----------------------*/
/* --- Mobile: (86)13922805190 -------------------------------------*/
/* --- Fax: 86-755-82944243 ----------------------------------------*/
/* --- Tel: 86-755-82948412 ----------------------------------------*/
/* --- Web: www.STCMCU.com -----------------------------------------*/
/* 如果要在程序中使用或者在文章中引用该程序,请在程序中或文章中注明  */
/* 使用了宏晶科技的资料或程序                                       */
/*------------------------------------------------------------------*/

#include<STC12C5A.h>
#include "absacc.h"

sbit en=P3^2;  //MAX485使能控制IO
sbit led1=P4^1;

sbit seg5=P2^4;
sbit seg6=P2^5;
sbit seg7=P2^6;


#define seg_duan P0

char code seg_yang[]={0x40, 0xf9, 0x24, 0xa0, 0x91, 0x82, 0x02, 0xf8, 0x00, 0x80};//共阳

/*定义常数*/

#define FOSC 11059200L                  //系统时钟频
#define BAUD (256 - FOSC/32/19200)     //定义串口波特率

#define MAX_SIZE 118                    //用户程序最大的可用扇区数

#define ENABLE_IAP  0x82                //系统工作频率<20MHz


typedef unsigned char BYTE;
typedef unsigned int WORD;
typedef struct
{
    BYTE cmd;
    WORD addr;
    WORD len;
    BYTE chk;
} CBW;

void Isp_Check(BYTE *p);
BYTE Isp_RecvUart();
void Isp_RecvBlock(BYTE *p, BYTE n);
void Isp_SendUart(BYTE dat);
void Isp_SoftReset();

BYTE cnt7f;                             //Isp_Check内部使用的变量,接收7F的计数器,当连续接收到16次7F后进入ISP下载模式
CBW cbw;                                //串口命令块
BYTE sum;                               //校验和变量
BYTE buf[64];                           //数据缓冲区

/*------------------------------------------------
  串口中断服务程序
------------------------------------------------*/
void uart() interrupt 4
{
    if (TI) TI = 0;                     //发送完成中断
    if (RI)                             //接收完成中断
    {
        Isp_Check(&cnt7f);              //ISP检测        
RI = 0; //清接收完成标志
    }
}
void delayms(int xms)//延时函数
{
 for(;xms>0;xms--);
}
void main()
{
    SCON = 0x50;                        //定义串口模式为8bit可变,无校验位
    AUXR = 0x15;                        //波特率发生器12倍速,并启动波特率发生器定时器
    BRT = BAUD;                         //初始化波特率发生器定时器的定时初值
    ES = 1;                             //使能串口中断
    EA = 1;                             //打开全局中断开关
en=0;
    while (1)
{
led1=~led1;
   delayms(5000);
}
}

/*------------------------------------------------
  串口ISP命令序列检测模块
------------------------------------------------*/
void Isp_Check(BYTE *p)
{
    BYTE i;
    WORD j;
    if (SBUF != 0x7f)                   //检测串口数据是否为7F
    {
        *p = 0;                         //若不是7F,则清7F计数值
// Isp_SoftReset();            //接收到非法命令时,复位系统
    }
    else
    {
        (*p)++; //若是7F,则7F计数值+1
        if (*p>=16)                   //判断7F是否已连续接收到16次
        {                               //若>=16次,则进入ISP下载模式  
IE = 0;                     //关闭所有中断
            PSW = 0;                    //ISP模块使用第0组寄存器
            SP = 0x5f;                  //重置ISP模块的堆栈指针
            RI = 0;                     //清除串口接收标志
            TI = 0;                     //置串口发送标志
            Isp_SendUart(0x5a);         //返回5A 69到PC,表示ISP模块已准备就绪  
            Isp_SendUart(0x69);         //返回5A 69到PC,表示ISP模块已准备就绪  

while (1)                   //ISP下载模式,主循环
            {
               sum = 0;                //清校验和           //若命令出错,则程序复位
               if((Isp_RecvUart()==0x5a)&&(Isp_RecvUart()==0x69))
                {
                   Isp_RecvBlock((BYTE *)&cbw, 6); //接收6字节的命令序列
                    if (sum != 0)                   //判断命令序列是否正确
                    {
                        Isp_SoftReset();            //若命令出错,则程序复位
                    }
                    switch (cbw.cmd)
                    {
                    case 0:                         //0号命令为擦除命令
                        IAP_ADDRL = 0;              //从第0扇区开始擦除
                        IAP_ADDRH = 0;
                        IAP_CONTR = ENABLE_IAP;     //使能IAP功能
                        IAP_CMD = 3;                //擦除命令
                        if (cbw.len > MAX_SIZE)     //判断擦除扇区数是否超出范围
                        {
                            cbw.len = MAX_SIZE;
                        }
                        while (cbw.len--)           //判断是否擦除完成
                        {
                            WDT_CONTR = 0x17;       //清看门狗
                            IAP_TRIG = 0x5a;        //触发ISP命令
                            IAP_TRIG = 0xa5;
                            IAP_ADDRH += 2;         //目标地址+512
                        }
                        Isp_SendUart(0);            //正确返回
                        break;
                    case 1:                         //1号命令为编程命令
                        sum = 0;                    //清除校验和值
                        Isp_RecvBlock(buf, 64);     //接收64字节的编程数据
                        Isp_RecvUart();             //接收校验和
                        if (sum != 0)               //判断数据是否正确
                        {
                            Isp_SoftReset();        //若数据出错,则程序复位
                        }
                        IAP_CONTR = ENABLE_IAP;     //使能IAP功能
                        IAP_CMD = 2;                //编程命令
                        j = cbw.addr;               //编程目标地址
                        for (i=0; i<64; i++)        //编程64字节数据
                        {
                            WDT_CONTR = 0x17;       //清看门狗
                            IAP_DATA = buf;      //将当前数据送IAP数据寄存器
                            IAP_ADDRL = j;          //目标地址送IAP地址寄存器
                            IAP_ADDRH = j >> 8;
                            IAP_TRIG = 0x5a;        //触发ISP命令
                            IAP_TRIG = 0xa5;
                            j++;                    //目标地址+1
                        }
                        j = cbw.addr;               //校验目标地址
                        for (i=0; i<64; i++)        //校验64字节数据
                        {
                            WDT_CONTR = 0x17;       //清看门狗
                            if (buf != CBYTE[j]) //源数据与目标数据进行比较
                                break;              //不相等,则编程出错
                            j++;                    //校验下一个字节
                        }
                        Isp_SendUart(!(i == 64));   //校验成功返回0; 否则返回1
                        break;
                    default:
                        Isp_SoftReset();            //接收到非法命令时,复位系统
                        break;
                    }
                } 
            }
        }
    }
}

/*------------------------------------------------
  接收一块串口数据
  入口参数: R0 (数据缓冲区地址)
            R7 (缓冲区长度)
------------------------------------------------*/
void Isp_RecvBlock(BYTE *p, BYTE n)
{
    while (n--)                         //检测长度
    {
        *p = Isp_RecvUart();            //接收1字节,并保存到缓冲区
        p++;                            //缓冲区地址+1
    }
}
/*------------------------------------------------
  接收1字节串口数据
  出口参数: ACC (接收到的数据)
------------------------------------------------*/
BYTE Isp_RecvUart()
{
    BYTE dat;
RI = 0;                     //清除串口接收标志
en=0;
while (!RI)                         //等待接收完成
    {
        WDT_CONTR = 0x17;               //清看门狗
    }
    dat = SBUF;                         //读取串口数据
    RI = 0;                             //清除标志
sum += dat;                         //计算校验和
    return dat;                         //返回接收到的串口数据
}
/*------------------------------------------------
  发送1字节串口数据 
  入口参数: ACC (待发送的数据) 
------------------------------------------------*/
void Isp_SendUart(BYTE dat)
{
    en=1;
    TI = 0;                             //清除标志
    SBUF = dat;                         //发送当前数据
while (!TI)                         //等待前一个数据发送完成
    {
       WDT_CONTR = 0x17;               //清看门狗
    }
en=0;
}

/*------------------------------------------------
  软件复位
------------------------------------------------*/
void Isp_SoftReset()
{
    IAP_CONTR = 0x20;                   //用户程序区复位
}
想问下这段

            Isp_SendUart(0x5a);         //返回5A 69到PC,表示ISP模块已准备就绪  
            Isp_SendUart(0x69);         //返回5A 69到PC,表示ISP模块已准备就绪  

while (1)                   //ISP下载模式,主循环
            {
               sum = 0;                //清校验和           //若命令出错,则程序复位
               if((Isp_RecvUart()==0x5a)&&(Isp_RecvUart()==0x69))
”为什么这两个返回值可以进行与操作啊?不是先发送0x5a,再发送0x69么?按理说返回值应该没有0x5a了啊,不是因该被后者顶替掉了么,我是把那两个子函数当作变量来理解的,希望大神帮我解惑。。。万分感谢

最佳答案

查看完整内容[请看2#楼]

两次接收从左到右先后执行的,所以可以收到不同的值啊
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

4

主题

200

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
236
金钱
236
注册时间
2012-12-19
在线时间
0 小时
发表于 2014-8-5 11:33:22 | 显示全部楼层
两次接收从左到右先后执行的,所以可以收到不同的值啊
目前在玩STM32,BBB,RPi
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165309
金钱
165309
注册时间
2010-12-1
在线时间
2108 小时
发表于 2014-8-5 23:19:26 | 显示全部楼层
帮顶。。。。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

19

主题

64

帖子

0

精华

初级会员

Rank: 2

积分
160
金钱
160
注册时间
2014-5-23
在线时间
0 小时
 楼主| 发表于 2014-8-6 08:52:57 | 显示全部楼层
回复【3楼】w0rmis20:
---------------------------------
1.执行“(Isp_RecvUart()==0x5a)”的时候,这个“Isp_RecvUart()”函数值不是0x69了么?
2.“case 1:                         //1号命令为编程命令
                        sum = 0;                    //清除校验和值
                        Isp_RecvBlock(buf, 64);     //接收64字节的编程数据
                        Isp_RecvUart();             //接收校验和
                        if (sum != 0)               //判断数据是否正确”
为什么sum=0就是数据正确,但是执行前面的语句时,sum不是一直和接收的数据累加么?怎么会等于0呀?
大神,我是菜鸟,希望别嫌弃帮我解答啦
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
22
金钱
22
注册时间
2015-2-28
在线时间
0 小时
发表于 2016-5-18 09:01:17 | 显示全部楼层
LVsler 发表于 2014-8-6 08:52
回复【3楼】w0rmis20:
---------------------------------
1.执行“(Isp_RecvUart()==0x5a)”的时候,这个 ...

假如升级第一个包为:
02 00 26 75 98 50 75 8E 15 75 9C FA D2 AC D2 AF 05 80 80 FC 03 11 00 01 00 00 8A 83 89 82 E4 73 FF FF FF 02 00 B2 78 7F E4 F6 D8 FD 75 81 13 02 00 6D 02 00 03 E4 93 A3 F8 E4 93 A3 40 03 F6 80        
PC端下发了上面的数据包后,再接着下发1B ,此时下发1B 与上面下发的累加和为0判断数据是否正确,故sum=0就是数据正确

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-23 15:44

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表