📄 main.c
字号:
/****************************************Copyright (c)**************************************************
** Guangzou ZLG-MCU Development Co.,LTD.
** graduate school
** http://www.zlgmcu.com
**
**--------------File Info-------------------------------------------------------------------------------
** File name: main.c
** Last modified Date: 2004-09-16
** Last Version: 1.0
** Descriptions: The main() function example template
**
**------------------------------------------------------------------------------------------------------
** Created by: Chenmingji
** Created date: 2004-09-16
** Version: 1.0
** Descriptions: The original version
**
**------------------------------------------------------------------------------------------------------
** Modified by: LinEnqiang
** Modified date: 2006-12-1
** Version:
** Descriptions: Test
**
********************************************************************************************************/
#include "config.h"
#include "IAP.h"
#include "GPIO.h"
#include "string.h"
#include "VIC.h"
#include "User.h"
#define LOW 0x00008000 // LOW区首地址
#define HIGH 0x00010000 // HIGH区首地址
#define Flag 0x00003000 // 用户程序标志区,0x55-运行LOW区代码,0xaa-运行HIGH区代码
#define LED1 (1 << 15) // P0.15控制LED1
#define UserISP (1 << 6) // 用户ISP跳线,P0.6。上电为低时,进入用户ISP代码区域
#define RxHardFIFO_Size 8
#define User_Flag 0x00004000 // 用户程序标志区
// 0x10000 -HIGH区,0x10000
// 0xffffffff-LOW区 ,0x8000
// 0x8000 -LOW区 ,0x8000
#define Ethernet_RAM 0x7FE00000 // 以太网RAM起始地址
#define User_LOW 0x00008000 // 用户程序低区入口
#define User_HIGH 0x00010000 // 用户程序高区入口
__align(4) uint8 IAP_Tmp[4096]; // 定义4K空间,编程Flash时使用
uint8 *RcvData = (uint8 *)Ethernet_RAM; // 接收数据缓冲区
uint32 *FlagPoint = (uint32 *)User_Flag; // 用户程序标志指针
volatile uint32 RcvCount; // 接收字节数
volatile uint8 RcvOver; // 接收完成标志 1:表示完成
/*********************************************************************************************************
** 函数名称:UART0_ISR
** 函数功能:串口中断服务函数。
********************************************************************************************************/
void __irq UART0_ISR(void)
{
volatile uint8 i;
T0TCR |= 0x02; // 定时器复位
T0TCR = 0x01;
do
{
switch (U0IIR & 0x0e)
{
case 0x04: // 接收中断,FIFO满中断
for (i = 0; i < RxHardFIFO_Size - 1; i++)
{
RcvData[RcvCount++] = U0RBR;
}
break;
case 0x0c: // 接收超时中断
while ((U0LSR & 0x01) != 0)
{
RcvData[RcvCount++] = U0RBR;
}
RcvOver = 1; // 接收完成
break;
case 0x02: // 发送中断
break;
case 0x06:
i = U0LSR;
break;
default:
break;
}
}while ((U0IIR & 0x01) == 0);
VICVectAddr = 0x00;
}
/*********************************************************************************************************
** 函数名称: UART_SendData
** 功能描述: UART发送函数。
** 入口参数: SendBuf 发送缓冲区
** len 发送字节数
** 出口参数: 无
********************************************************************************************************/
void UART0_SendData(uint8 *SendBuf, uint32 len)
{
while (len != 0)
{
U0THR = *SendBuf++; // 发送数据
U0TER = 0x80;
while ((U0LSR & 0x20) == 0);// 等待数据发送完毕
len --;
}
}
/*********************************************************************************************************
** 函数名称: uint8 T0MAT_Init
** 功能描述: 定时器0匹配模式初始化
** 入口参数: time 匹配时间,该值会直接写入到匹配寄存器中
** PR_data 预分频寄存器的值
** T_MODE 匹配控制模式
** 0:匹配时,定时器复位
** 1:匹配时,定时器停止
** EXT_MODE 匹配时,外部输出控制
** 0:不执行任何动作
** 1:外部匹配输出0
** 2:外部匹配输出1
** 3:外部匹配输出翻转
** MATn 匹配通道选择,0~3
** Int_En 中断使能
** 0:发生匹配事件时,不产生中断
** 1:发生匹配事件时,产生中断
** 出口参数: 0 :初始化失败
** 1 :初始化成功
** 调试说明:调用前,要设置相关的引脚
********************************************************************************************************/
uint8 T0MAT_Init(uint32 time, uint32 PR_data, uint8 T_MODE, uint8 EXT_MODE, uint8 MATn, uint8 Int_En)
{
if ((T_MODE > 1) || (EXT_MODE > 3) || (MATn > 3) || (Int_En > 1))
{
return (0); // 参数不合理,直接返回
}
T0TCR = 0x03; // 在设置之前,先将定时器复位
T0IR = T0IR | (1 << MATn); // 清除中断标志位
T0PR = PR_data; // 设置预分频器
/* 设置匹配寄存器 */
switch(MATn)
{
case 0:
T0MR0 = time;
break;
case 1:
T0MR1 = time;
break;
case 2:
T0MR2 = time;
break;
case 3:
T0MR3 = time;
break;
default:
break;
}
T0MCR = T0MCR & (~(7 << (MATn * 3))) | (1 << (MATn * 3 + 1 + T_MODE)) | (Int_En << (MATn * 3));
T0EMR = T0EMR & (~(3 << (MATn * 2 + 4))) | (EXT_MODE << (MATn * 2 + 4));
T0TCR = 0x01; // 重新启动定时器
return (1);
}
/*********************************************************************************************************
** 函数名称: UART0_Init
** 功能描述: 对UART0进行初始化
** 入口参数: baud 串口通信波特率
** 出口参数: 无
********************************************************************************************************/
void UART0_Init(uint32 baud)
{
PCONP |= (1 << 3);
/* 设置UART0引脚,且不影响其它引脚 */
PINSEL0 = (PINSEL0 & (~(0x0f << 4))) | (1 << 4) | (1 << 6);
/* 设置串口波特率 */
U0LCR = 0x80;
U0DLM = ((Fpclk / 16) / baud) / 256;
U0DLL = ((Fpclk / 16) / baud) % 256;
/* 设置串口模式:8位数据位、1位停止位、无奇偶校验位 */
U0LCR = 0x03;
U0FCR = 0x81; // FIFO触发点为8个字节
U0IER = 0x01; // 接收中断使能
IRQ_Init(UART0_INT, 0, (uint32)UART0_ISR); // 初始化UART IRQ中断信息
}
/*********************************************************************************************************
** 函数名称: SendMessage
** 功能描述: 发送提示信息。
** 入口参数: 无
** 出口参数: 无
********************************************************************************************************/
void SendMessage(void)
{
volatile uint8 tmp; // 用来清除UART中断标志
if (*FlagPoint == 0x10000) // 当前程序运行在HIGH区,需要对LOW区进行升级
{
UART0_SendData((uint8 *)("当前程序运行在HIGH区,只能对LOW区进行升级 "), strlen("当前程序运行在HIGH区,只能对LOW区进行升级 "));
}
else
{
if (*FlagPoint == 0x8000) // 当前程序运行在HIGH区,需要对LOW区进行升级
{
UART0_SendData((uint8 *)("当前程序运行在LOW区,只能对HIGH区进行升级 "), strlen("当前程序运行在LOW区,只能对HIGH区进行升级 "));
}
else // 当前程序运行在HIGH区,需要对LOW区进行升级
{
UART0_SendData((uint8 *)("当前程序运行在固件区,只能对HIGH区进行升级 "), strlen("当前程序运行在固件区,只能对HIGH区进行升级 "));
}
}
tmp = U0IIR;
}
/*********************************************************************************************************
** 函数名称: ProgramUserData
** 功能描述: 编程用户代码区
** 入口参数: 无
** 出口参数: 无
********************************************************************************************************/
void ProgramUserData(void)
{
uint32 Addr; // Addr:字节偏移量
uint32 ProgramCount; // ProgramCount:编程到Flash扇区的字节数
if (*FlagPoint == 0x10000) // 当前程序运行在HIGH区,需要对LOW区进行升级
{
SelSector (8, 8); // 选择LOW扇区
EraseSector(8, 8); // 擦除LOW扇区
}
else // 当前程序运行在LOW区固件区 ,需要对HIGH区进行升级
{
SelSector (9, 9); // 选择HIGH扇区
EraseSector(9, 9); // 擦除HIGH扇区
}
Addr = 0; // 字节偏移量清0
while (RcvCount != 0)
{
if (RcvCount > (1024 * 4)) // 一次最多写入4K代码量
{
memcpy(IAP_Tmp , RcvData + Addr, 1024 * 4);
RcvCount -= (1024 * 4);
ProgramCount = 1024 * 4;
}
else
{
memcpy(IAP_Tmp , RcvData + Addr, RcvCount);
ProgramCount = RcvCount;
RcvCount = 0;
if ((ProgramCount == 256) || (ProgramCount == 512) || (ProgramCount == 1024) || (ProgramCount == 4096))
{
goto ProgramFlash;
}
/* 满足编程字节数的要求,256、512、1024等 */
if (ProgramCount < 256)
{
ProgramCount = 256;
goto ProgramFlash;
}
if (ProgramCount < 512)
{
ProgramCount = 512;
goto ProgramFlash;
}
if (ProgramCount < 1024)
{
ProgramCount = 1024;
goto ProgramFlash;
}
if (ProgramCount < 4096)
{
ProgramCount = 4096;
goto ProgramFlash;
}
}
ProgramFlash:
/* 升级用户程序空间 */
if (*FlagPoint == 0x10000) // 当前程序运行在HIGH区,需要对LOW区进行升级
{
SelSector(8, 8); // 选择LOW扇区
RamToFlash(User_LOW + Addr, (uint32)IAP_Tmp, ProgramCount); // 写数据到FLASH
Addr += ProgramCount;
}
else // 当前程序运行在LOW区,需要对HIGH区进行升级
{
SelSector(9, 9); // 选择HIGH扇区
RamToFlash(User_HIGH + Addr, (uint32)IAP_Tmp, ProgramCount);// 写数据到FLASH
Addr += ProgramCount;
}
}//end of while(RcvCount != 0)
}
/*********************************************************************************************************
** 函数名称: UpdateUserFlag
** 功能描述: 更新用户程序标志区
** 入口参数: 无
** 出口参数: 无
********************************************************************************************************/
void UpdateUserFlag(void)
{
uint32 *Data32Point;
/* 更新用户程序标志空间0x4000 */
memset(IAP_Tmp, 0xff, 256); // 临时缓冲区清空
Data32Point = (uint32 *)IAP_Tmp;
if (*FlagPoint == 0x10000)
{
*Data32Point = 0x8000;
}
else
{
*Data32Point = 0x10000;
}
SelSector (4, 4); // 选择扇区
EraseSector(4, 4); // 擦除扇区
SelSector (4, 4); // 选择扇区
RamToFlash(User_Flag, (uint32)IAP_Tmp, 256); // 编程FLASH
}
/*********************************************************************************************************
** 函数名称:main
** 函数功能:在线升级函数Boot代码
** 调试说明:在Flash中调试
********************************************************************************************************/
int main (void)
{
void (*UserProgram)(); //函数指针
uint32 dly;
PCONP |= (1 << 30);
UART0_Init(9600); // 初始化UART0
GPIO0_Init(LED1, 1);
GPIO0_Init(UserISP, 0); // 输入模式
SendMessage(); // 发送提示信息
memset(IAP_Tmp, 0, 4096); // 缓冲区清零
memset((char *)RcvData, 0, 1024 * 8);
if ((Read_P0() & UserISP) == 0)
{
/* 进入升级阶段 */
T0MAT_Init(Fpclk * 30, 0, 1, 0, 0, 1); // 30秒钟定时
RcvOver = 0;
RcvCount = 0;
while (RcvOver == 0)
{
if ((T0IR & 0x01) != 0)
{
T0IR = 0x01; // 清除中断标志
RcvCount = 0;
break; // 时间到,退出接收程序
}
}
if (RcvCount != 0) // 升级用户代码
{
IRQDisable();
ProgramUserData(); // 编程用户代码区
UpdateUserFlag(); // 更新用户程序标志区
IRQEnable();
}
}
/* 运行用户程序 */
if (*FlagPoint == HIGH)
{
UserProgram = (void (*)()) (HIGH);
}
else
{
if (*FlagPoint == LOW)
{
UserProgram = (void (*)()) (LOW);
}
else
{
while (1)
{
P0_GPIOClr(LED1);
for (dly = 5000000 ; dly != 0; dly --);
P0_GPIOSet(LED1);
for (dly = 5000000 ; dly != 0; dly --);
}
}
}
(*UserProgram)(); // 启动程序
return (0);
}
/*********************************************************************************************************
** End Of File
********************************************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -