整理了部分苏州大学K60嵌入式培训的代码。
#include "includes.h"
void main(void)
{
//1 主程序使用的变量定义
uint32 runcount; //运行计数器
//2 关中断
DisableInterrupts; //禁止总中断
//3 模块初始化
light_init(Light_Run_PORT,Light_Run1,Light_OFF); //指示灯初始化
light_init(Light_Run_PORT,Light_Run2,Light_ON); //指示灯初始化
//4 开中断
//主循环
while(1)
{
//1 主循环计数到一定的值,使小灯的亮、暗状态切换
runcount++;
if(runcount>=5000000)
{
light_change(Light_Run_PORT,Light_Run1);//指示灯的亮、暗状态切换
light_change(Light_Run_PORT,Light_Run2);//指示灯的亮、暗状态切换
runcount=0;
}
}
}
//-------------------------------------------------------------------------*
// 文件名:sysinit.c *
// 说 明: 系统配置文件 *
//-------------------------------------------------------------------------*
#include "sysinit.h" //头文件
//全局变量声明
int core_clk_khz;
int core_clk_mhz;
int periph_clk_khz;
//-------------------------------------------------------------------------*
//函数名: sysinit *
//功 能: 系统设置 *
//参 数: 无 *
//返 回: 无 *
//说 明: 无 *
//-------------------------------------------------------------------------*
void sysinit (void)
{
//使能IO端口时钟
SIM_SCGC5 |= (SIM_SCGC5_PORTA_MASK
| SIM_SCGC5_PORTB_MASK
| SIM_SCGC5_PORTC_MASK
| SIM_SCGC5_PORTD_MASK
| SIM_SCGC5_PORTE_MASK );
//开启系统时钟
core_clk_mhz = pll_init(CORE_CLK_MHZ, REF_CLK);
//通过pll_init函数的返回值来计算内核时钟和外设时钟
core_clk_khz = core_clk_mhz * 1000;
periph_clk_khz = core_clk_khz / (((SIM_CLKDIV1 & SIM_CLKDIV1_OUTDIV2_MASK) >> 24)+ 1);
//使能跟踪时钟,用于调试
trace_clk_init();
//FlexBus时钟初始化
fb_clk_init();
}
//-------------------------------------------------------------------------*
//函数名: trace_clk_init *
//功 能: 跟踪时钟初始化 *
//参 数: 无 *
//返 回: 无 *
//说 明: 用于调试 *
//-------------------------------------------------------------------------*
void trace_clk_init(void)
{
//设置跟踪时钟为内核时钟
SIM_SOPT2 |= SIM_SOPT2_TRACECLKSEL_MASK;
//在PTA6引脚上使能TRACE_CLKOU功能
PORTA_PCR6 = ( PORT_PCR_MUX(0x7));
}
//-------------------------------------------------------------------------*
//函数名: fb_clk_init *
//功 能: FlexBus时钟初始化 *
//参 数: 无 *
//返 回: 无 *
//说 明: *
//-------------------------------------------------------------------------*
void fb_clk_init(void)
{
//使能FlexBus模块时钟
SIM_SCGC7 |= SIM_SCGC7_FLEXBUS_MASK;
//在PTA6引脚上使能FB_CLKOUT功能
PORTC_PCR3 = ( PORT_PCR_MUX(0x5));
}
//-------------------------------------------------------------------------*
//函数名: pll_init *
//功 能: pll初始化 *
//参 数: clk_option:时钟选项 *
// crystal_val:时钟值 *
//返 回: 时钟频率值 *
//说 明: *
//-------------------------------------------------------------------------*
unsigned char pll_init(unsigned char clk_option, unsigned char crystal_val)
{
unsigned char pll_freq;
if (clk_option > 3) {return 0;} //如果没有选择可用的选项则返回0
if (crystal_val > 15) {return 1;} // 如果如果可用的晶体选项不可用则返回1
//这里处在默认的FEI模式
//首先移动到FBE模式
#if (defined(K60_CLK) || defined(ASB817))
MCG_C2 = 0;
#else
//使能外部晶振
MCG_C2 = MCG_C2_RANGE(2) | MCG_C2_HGO_MASK | MCG_C2_EREFS_MASK;
#endif
//初始化晶振后释放锁定状态的振荡器和GPIO
SIM_SCGC4 |= SIM_SCGC4_LLWU_MASK;
LLWU_CS |= LLWU_CS_ACKISO_MASK;
//选择外部晶振,参考分频器,清IREFS来启动外部晶振
MCG_C1 = MCG_C1_CLKS(2) | MCG_C1_FRDIV(3);
//等待晶振稳定
#if (!defined(K60_CLK) && !defined(ASB817))
while (!(MCG_S & MCG_S_OSCINIT_MASK)){};
#endif
//等待参考时钟状态位清零
while (MCG_S & MCG_S_IREFST_MASK){};
//等待时钟状态位显示时钟源来自外部参考时钟
while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x2){};
//进入FBE模式
#if (defined(K60_CLK))
MCG_C5 = MCG_C5_PRDIV(0x18);
#else
//配置PLL分频器来匹配所用的晶振
MCG_C5 = MCG_C5_PRDIV(crystal_val);
#endif
//确保MCG_C6处于复位状态,禁止LOLIE、PLL、和时钟控制器,清PLL VCO分频器
MCG_C6 = 0x0;
//选择PLL VCO分频器,系统时钟分频器取决于时钟选项
switch (clk_option) {
case 0:
//设置系统分频器
//MCG=PLL, core = MCG, bus = MCG, FlexBus = MCG, Flash clock= MCG/2
set_sys_dividers(0,0,0,1);
//设置VCO分频器,使能PLL为50MHz, LOLIE=0, PLLS=1, CME=0, VDIV=1
MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(1); //VDIV = 1 (x25)
pll_freq = 50;
break;
case 1:
//设置系统分频器
//MCG=PLL, core = MCG, bus = MCG/2, FlexBus = MCG/2, Flash clock= MCG/4
set_sys_dividers(0,1,1,3);
//设置VCO分频器,使能PLL为100MHz, LOLIE=0, PLLS=1, CME=0, VDIV=26
MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(26); //VDIV = 26 (x50)
pll_freq = 100;
break;
case 2:
//设置系统分频器
//MCG=PLL, core = MCG, bus = MCG/2, FlexBus = MCG/2, Flash clock= MCG/4
set_sys_dividers(0,1,1,3);
//设置VCO分频器,使能PLL为96MHz, LOLIE=0, PLLS=1, CME=0, VDIV=24
MCG_C6 = MCG_C6_PLLS_MASK | MCG_C6_VDIV(24); //VDIV = 24 (x48)
pll_freq = 96;
break;
case 3:
//设置系统分频器
//MCG=PLL, core = MCG, bus = MCG, FlexBus = MCG, Flash clock= MCG/2
set_sys_dividers(0,0,0,1);
//设置VCO分频器,使能PLL为48MHz, LOLIE=0, PLLS=1, CME=0, VDIV=0
MCG_C6 = MCG_C6_PLLS_MASK; //VDIV = 0 (x24)
pll_freq = 48;
break;
}
while (!(MCG_S & MCG_S_PLLST_MASK)){}; // wait for PLL status bit to set
while (!(MCG_S & MCG_S_LOCK_MASK)){}; // Wait for LOCK bit to set
//进入PBE模式
//通过清零CLKS位来进入PEE模式
// CLKS=0, FRDIV=3, IREFS=0, IRCLKEN=0, IREFSTEN=0
MCG_C1 &= ~MCG_C1_CLKS_MASK;
//等待时钟状态位更新
while (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x3){};
//开始进入PEE模式
return pll_freq;
}
//-------------------------------------------------------------------------*
//函数名: set_sys_dividers *
//功 能: 设置系系统分频器 *
//参 数: 预分频值 *
//返 回: 无 *
//说 明: 此函数必须放在RAM里执行,否则会产生错误e2448。当FLASH时钟分频改变*
// 时,必须禁止FLASH的预取功能。在时钟分频改变之后,必须延时一小段时*
// 间才可以从新使能预取功能。 *
//-------------------------------------------------------------------------*
__ramfunc void set_sys_dividers(uint32 outdiv1, uint32 outdiv2, uint32 outdiv3, uint32 outdiv4)
{
uint32 temp_reg;
uint8 i;
//保存FMC_PFAPR当前的值
temp_reg = FMC_PFAPR;
//通过M&PFD置位M0PFD来禁止预取功能
FMC_PFAPR |= FMC_PFAPR_M7PFD_MASK | FMC_PFAPR_M6PFD_MASK | FMC_PFAPR_M5PFD_MASK
| FMC_PFAPR_M4PFD_MASK | FMC_PFAPR_M3PFD_MASK | FMC_PFAPR_M2PFD_MASK
| FMC_PFAPR_M1PFD_MASK | FMC_PFAPR_M0PFD_MASK;
//给时钟分频器设置期望值
SIM_CLKDIV1 = SIM_CLKDIV1_OUTDIV1(outdiv1) | SIM_CLKDIV1_OUTDIV2(outdiv2)
| SIM_CLKDIV1_OUTDIV3(outdiv3) | SIM_CLKDIV1_OUTDIV4(outdiv4);
//等待分频器改变
for (i = 0 ; i < outdiv4 ; i++)
{}
//从新存FMC_PFAPR的原始值
FMC_PFAPR = temp_reg;
return;
}
//-------------------------------------------------------------------------*
// 文件名: common.h (通用头文件) *
// 说 明: *
//-------------------------------------------------------------------------*
#include "common.h"
//-------------------------------------------------------------------------*
//函数名: stop *
//功 能: 设置CPU为STOP模式 *
//参 数: 无 *
//返 回: 无 *
//说 明: 无 *
//-------------------------------------------------------------------------*
void stop (void)
{
//置位SLEEPDEEP来使能STOP模式
SCB_SCR |= SCB_SCR_SLEEPDEEP_MASK;
//进入STOP模式
asm("WFI");
}
//-------------------------------------------------------------------------*
//函数名: wait *
//功 能: 设置CPU为WAIT模式 *
//参 数: 无 *
//返 回: 无 *
//说 明: 无 *
//-------------------------------------------------------------------------*
void wait (void)
{
//清SLEEPDEEP位来确定进入WAIT模式
SCB_SCR &= ~SCB_SCR_SLEEPDEEP_MASK;
//进入WAIT模式
asm("WFI");
}
//-------------------------------------------------------------------------*
//函数名: write_vtor *
//功 能: 更改中断向量表偏移寄存器的值 *
//参 数: 要更改的值 *
//返 回: 无 *
//说 明: 无 *
//-------------------------------------------------------------------------*
void write_vtor (int vtor)
{
//写新值
SCB_VTOR = vtor;
}
//-------------------------------------------------------------------------*
//函数名: enable_irq *
//功 能: 使能irq中断 *
//参 数: irq:irq号 *
//返 回: 无 *
//说 明: irq号不是中断向量号 *
//-------------------------------------------------------------------------*
void enable_irq (int irq)
{
int div;
//确定irq号为有效的irq号
if (irq > 91) irq=91;
//确定对应的NVICISER
div = irq/32;
switch (div)
{
case 0x0:
NVICICPR0 = 1 << (irq%32);
NVICISER0 = 1 << (irq%32);
break;
case 0x1:
NVICICPR1 = 1 << (irq%32);
NVICISER1 = 1 << (irq%32);
break;
case 0x2:
NVICICPR2 = 1 << (irq%32);
NVICISER2 = 1 << (irq%32);
break;
}
}
//-------------------------------------------------------------------------*
//函数名: disable_irq *
//功 能: 禁止irq中断 *
//参 数: irq:irq号 *
//返 回: 无 *
//说 明: irq号不是中断向量号 *
//-------------------------------------------------------------------------*
void disable_irq (int irq)
{
int div;
//确定irq号为有效的irq号
if (irq > 91) irq=91;
//确定对应的NVICISER
div = irq/32;
switch (div)
{
case 0x0:
NVICICER0 = 1 << (irq%32);
break;
case 0x1:
NVICICER1 = 1 << (irq%32);
break;
case 0x2:
NVICICER2 = 1 << (irq%32);
break;
}
}
//-------------------------------------------------------------------------*
//函数名: set_irq_priority *
//功 能: 设置irq中断和优先级 *
//参 数: irq:irq号 *
// prio:优先级 *
//返 回: 无 *
//说 明: irq号不是中断向量号 *
//-------------------------------------------------------------------------*
void set_irq_priority (int irq, int prio)
{
uint8 *prio_reg;
//确定irq号和优先级有效
if (irq > 91) irq=91;
if (prio > 15) prio=15;
//确定对应的NVICISER
prio_reg = (uint8 *)(((uint32)&NVICIP0) + irq);
//设置优先级
*prio_reg = ( (prio&0xF) << (8 - ARM_INTERRUPT_LEVEL_BITS) );
}