|  | 
 
| 鉴于大家学习方便,现给出C8051F340 Bootloader的代码架构,由于涉及商业信息,所以不能给出整个工程,请谅解! 相关文档信息,请参看blog: http://blog.ednchina.com/zhurunping/239751/message.aspx#
 
 // 项目名称: C8051F340 BootLoader
 // 版本介绍:
 // 1.4.2 该程序仅作学习测试使用, 请勿用作其他.
 //   介意使用内部晶振.
 /** 擦除一个分区 */
 #define flash_erase(addr)  D_MACRO_BEGIN \
 FLKEY = 0xA5; \
 FLKEY = 0xF1; \
 PSCTL  = 0x03; \
 *addr = 0x00; \
 PSCTL = 0x00; \
 D_MACRO_END
 /** 写入Flash一个字节*/
 #define flash_write(addr, x) D_MACRO_BEGIN \
 FLKEY = 0xA5; \
 FLKEY = 0xF1; \
 *(addr) = x; \
 D_MACRO_END
 /** 串口查询方式发送一字节数据*/
 #define Uart_PutCh(dat)   D_MACRO_BEGIN \
 SBUF1 = dat; \
 while ((SCON1&0x02) == 0); \
 SCON1 &= 0xFD; \
 D_MACRO_END
 #define D_APP_START  0x0000    // APP区起始地址
 #define D_APP_LIMIT  0xEE00    // APP区结束地址
 #define D_RUN_ADDRESS 0xEE00    // APP运行地址(只使用3Byte)
 #define D_BOOT_ADDR  0xF000    // Boot程序存储地址
 #define D_BOOT_LIMIT 0xF800    // Boot区结束地址
 #define D_FLASH_LIMIT 0xFA00    // FLASH可操作区结束地址
 
 /** 本地变量*/
 uint8 rst_addr[3];      // 用以保存启动向量
 uint8 xdata *pwrite;     // 指向代码区的指针
 uint8 code *pread;      // 指向代码区的指针
 uint8 dat;
 /** @func RTload
 * @brief 载入函数
 */
 static void
 RTload(void)
 {
 uint8 dat, tmp[4];
 uint16 i, size, dnCS, CheckSum;
 Uart_Print(">Start erasing flash...\n");
 /** 1. 保存boot入口地址, 最后回写 */
 pread = 0;
 rst_addr[0] = *pread++;
 rst_addr[1] = *pread++;
 rst_addr[2] = *pread++;
 /** 2. 准备扇区 */
 for (pwrite=0; pwrite<D_APP_LIMIT; pwrite+=0x200) { // APP区
 flash_erase(pwrite);
 }
 pwrite = D_RUN_ADDRESS;    // 启动参数区
 flash_erase(pwrite);
 Uart_Print(">Erasing complete.\n");
 /** 3. 回写boot入口地址 */
 PSCTL = 0x01;
 pwrite = 0;
 flash_write(pwrite++, rst_addr[0]);
 flash_write(pwrite++, rst_addr[1]);
 flash_write(pwrite++, rst_addr[2]);
 /** 4. 通知主机发送代码 */
 SCON1 |= B_REN1;
 Uart_Print(">Please transmit bin file...\n");
 /** 5. 读接收数据长度 */
 for (i=0; i<4; i++) {
 while ((SCON1&0x01) == 0);
 SCON1 &= 0xFE;
 tmp = SBUF1;
 }
 size = ((tmp[1]<<8)+tmp[0]) - 4 - 2;
 if (size > D_APP_LIMIT) {
 PSCTL = 0x00;
 Uart_Print(">Error: no enough space for your app!\n");
 return;
 }
 /** 6. 开始接收数据, 同时写入Flash APP区*/
 CheckSum= 0;
 pwrite = D_RUN_ADDRESS;    // 启动地址(3Byte)
 for (i=0; i<3; i++) {
 while ((SCON1&0x01) == 0);
 SCON1 &= 0xFE;
 dat = SBUF1;
 CheckSum += dat;
 flash_write(pwrite++, dat);
 }
 pwrite = 3;       // 程序区
 for (i=3; i<size; i++) {
 while ((SCON1&0x01) == 0);
 SCON1 &= 0xFE;
 dat = SBUF1;
 CheckSum += dat;
 flash_write(pwrite++, dat);
 }
 PSCTL = 0x00;       // 禁止Flash操作
 /** 7. 读校验和 */
 for (i=0; i<2; i++) {
 while ((SCON1&0x01) == 0);
 SCON1 &= 0xFE;
 tmp = SBUF1;
 }
 dnCS = (tmp[1]<<8) + tmp[0];
 Uart_Print(">Transmit complete.\n");
 /** 8. 校验数据*/
 if (dnCS != CheckSum) {
 Uart_Print(">CheckSum error!\n");
 } else {
 Uart_Print(">Programming Complete.\n");
 Uart_Print(">You have to restart the device to use the new firmware.\n");
 }
 }
 void
 main(void)
 {
 uint8 dat;
 uint16 timeout;
 void (*boot)( void);
 Init_Device();       // 初始化设备
 FLSCL = ((FLSCL&0xF0) | 0x09);  // 设置FLASH预分频器
 PFE0CN = PFE0CN & 0xFE;    // FLASH按字节写入
 // 此处读取Loader使能按键
 // ...
 if (1) { // 用户设置为下载模式
 /** 创建握手过程*/
 Uart_Print("\n");
 Uart_Print("****************ZBoot v1.4.2*****************\n");
 Uart_Print(">Please press 's' to start programming.\n");
 while (1) {
 //  此处判断读入's'
 // ...
 if ("键入正确") {
 RTload();     // Download
 } else if ("超时") {
 goto boot_out;
 }
 }
 }
 boot_out:
 pread = D_RUN_ADDRESS;
 if (*pread != 0x02) {
 Uart_Print(">Error: no app program for run!\n");
 while (1);
 }
 boot = D_RUN_ADDRESS;
 (*boot)();
 }
 
 
 | 
 |