前言
最近把一款产品的代码从新唐MS51移植到了中微8S6990平台上,记录下移植过程遇到的各种情况。
定时器初始化、中断服务函数
void TMR0_Config(void)
{
/*
(1)设置Timer的运行模式
*/
TMR_ConfigRunMode(TMR0, TMR_MODE_TIMING,TMR_TIM_16BIT);
/*
(2)设置Timer 运行时钟
*/
TMR_ConfigTimerClk(TMR0, TMR_CLK_DIV_12); /*Fsys = 24Mhz,Ftimer = 2Mhz,Ttmr=0.5us*/
/*
(3)设置Timer周期
*/
TMR_ConfigTimerPeriod(TMR0, (65535-2000)>>8, 65535-2000); // 2000*0.5us = 1000us,递增计数
/*
(4)开启中断
*/
TMR_EnableOverflowInt(TMR0);
/*
(5)设置Timer中断优先级
*/
IRQ_SET_PRIORITY(IRQ_TMR0,IRQ_PRIORITY_LOW);
/*
(6)开启Timer
*/
TMR_Start(TMR0);
}
void TMR1_Config(void)
{
/*
(1)设置Timer的运行模式
*/
TMR_ConfigRunMode(TMR1, TMR_MODE_TIMING,TMR_TIM_16BIT);
/*
(2)设置Timer 运行时钟
*/
TMR_ConfigTimerClk(TMR1, TMR_CLK_DIV_12); /*Fsys = 24Mhz,Ftimer = 2Mhz,Ttmr=0.5us*/
/*
(3)设置Timer周期
*/
TMR_ConfigTimerPeriod(TMR1, (65536-20000)>>8, 65536-20000); // 20000*0.5us = 10000us,递增计数
/*
(4)开启中断
*/
TMR_EnableOverflowInt(TMR1);
/*
(5)设置Timer中断优先级
*/
IRQ_SET_PRIORITY(IRQ_TMR1,IRQ_PRIORITY_LOW);
/*
(6)开启Timer
*/
TMR_Start(TMR1);
}
中断服务函数:
void Timer0_IRQHandler(void) interrupt TMR0_VECTOR
{
TH0 = (65535-2000)>>8; //1ms
TL0 = 65535-2000;
TF0 = 0; //可写可不写,进入中断硬件自动清零
}
void Timer1_IRQHandler(void) interrupt TMR1_VECTOR
{
TH1 = (65536-20000)>>8; //10ms
TL1 = 65536-20000;
TF1 = 0;
}
这两个是最基本的,没啥好说的,中断开起来之后就成功了一大半了。
GPIO配置
/*三个按键*/
GPIO_ENABLE_INPUT(P2TRIS,GPIO_PIN_4); //设置输入/输出模式
GPIO_ENABLE_INPUT(P2TRIS,GPIO_PIN_5);
GPIO_ENABLE_INPUT(P2TRIS,GPIO_PIN_6);
GPIO_ENABLE_UP(P2UP,GPIO_PIN_4); //开上拉
GPIO_ENABLE_UP(P2UP,GPIO_PIN_5);
GPIO_ENABLE_UP(P2UP,GPIO_PIN_6);
P24=1;P25=1;P26=1;
/*ADC输入检测*/
GPIO_ENABLE_INPUT(P3TRIS,GPIO_PIN_2);
/*空闲IO 全部设置为输出高电平*/
GPIO_ENABLE_OUTPUT(P3TRIS,GPIO_PIN_0);
GPIO_ENABLE_OUTPUT(P3TRIS,GPIO_PIN_1);
GPIO_ENABLE_OUTPUT(P3TRIS,GPIO_PIN_5);
GPIO_ENABLE_OUTPUT(P3TRIS,GPIO_PIN_6);
P30=1;P31=1;P35=1;P36=1;
GPIO_ENABLE_OUTPUT(P0TRIS,GPIO_PIN_5);
GPIO_ENABLE_OUTPUT(P0TRIS,GPIO_PIN_4);
P04=1;P05=1;
GPIO_ENABLE_OUTPUT(P2TRIS,GPIO_PIN_1);
GPIO_ENABLE_OUTPUT(P2TRIS,GPIO_PIN_2);
GPIO_ENABLE_OUTPUT(P2TRIS,GPIO_PIN_3);
P21=1;P22=1;P23=1;
ADC模数转换初始化
/******************************************************************************
** \brief ADC_Config
** \param [in]
**
** \return none
** \note
******************************************************************************/
void ADC_Config(void)
{
//设置ADC的运行模式
ADC_ConfigRunMode(ADC_CLK_DIV_256, ADC_RESULT_LEFT); //设置ADC时钟为系统时钟的256分频,ADC结果为左对齐,如有对ADC时钟有操作请参考"中微8051芯片ADC模块应用笔记"
//设置ADC转换通道
ADC_EnableChannel(ADC_CH_14);
GPIO_SET_MUX_MODE(P32CFG, GPIO_P32_MUX_AN14); //设置端口复用功能 设置为复用为模拟输入通道14
//设置ADC LDO 这个必须开启,相当于基准,6990是通过内部一个LDO来产生不同的基准的
ADC_EnableLDO();
ADC_ConfigADCVref(ADC_VREF_1P2V); //ADC_VREF_1P2V, ADC_VREF_2V, ADC_VREF_2P4V, ADC_VREF_3V
//设置ADC中断
ADC_DisableInt();
//开启ADC
ADC_Start();
}
PWM初始化
void PWM_Init(void)
{
//设置EPWM运行模式 独立模式
EPWM_ConfigRunMode(EPWM_OC_INDEPENDENT);
//设置EPWM运行时钟
EPWM_ConfigChannelClk(EPWM0,EPWM_CLK_DIV_32);
EPWM_ConfigChannelClk(EPWM1,EPWM_CLK_DIV_32);
EPWM_ConfigChannelClk(EPWM2,EPWM_CLK_DIV_32);
EPWM_ConfigChannelClk(EPWM3,EPWM_CLK_DIV_32);
EPWM_ConfigChannelClk(EPWM4,EPWM_CLK_DIV_32);
EPWM_ConfigChannelPeriod(EPWM0, 0x0190); //总周期 400(十进制)
EPWM_ConfigChannelPeriod(EPWM1, 0x0190);
EPWM_ConfigChannelPeriod(EPWM2, 0x0190);
EPWM_ConfigChannelPeriod(EPWM3, 0x0190);
EPWM_ConfigChannelPeriod(EPWM4, 0x0190);
EPWM_ConfigChannelSymDuty(EPWM0, 0x0000);
EPWM_ConfigChannelSymDuty(EPWM1, 0x0000);
EPWM_ConfigChannelSymDuty(EPWM2, 0x0000);
EPWM_ConfigChannelSymDuty(EPWM3, 0x0000);
EPWM_ConfigChannelSymDuty(EPWM4, 0x0000);
//设置EPWM的加载方式为自动加载
EPWM_EnableAutoLoadMode(EPWM_CH_0_MSK|EPWM_CH_1_MSK|EPWM_CH_2_MSK|EPWM_CH_3_MSK|EPWM_CH_4_MSK|EPWM_CH_5_MSK);
//设置EPWM的输出极性
EPWM_DisableReverseOutput(EPWM_CH_0_MSK|EPWM_CH_1_MSK|EPWM_CH_2_MSK|EPWM_CH_3_MSK|EPWM_CH_4_MSK); //关闭反向输出
//设置EPWM输出
EPWM_EnableOutput(EPWM_CH_0_MSK|EPWM_CH_1_MSK|EPWM_CH_2_MSK|EPWM_CH_3_MSK|EPWM_CH_4_MSK); //开启输出
//设置EPWM死区 失能
EPWM_DisableDeadZone(EPWM0);
EPWM_DisableDeadZone(EPWM1);
EPWM_DisableDeadZone(EPWM2);
EPWM_DisableDeadZone(EPWM3);
EPWM_DisableDeadZone(EPWM4);
//设置EPWM输出IO复用
GPIO_SET_MUX_MODE(P13CFG, GPIO_MUX_PG0);
GPIO_SET_MUX_MODE(P14CFG, GPIO_MUX_PG1);
GPIO_SET_MUX_MODE(P15CFG, GPIO_MUX_PG2);
GPIO_SET_MUX_MODE(P16CFG, GPIO_MUX_PG3);
GPIO_SET_MUX_MODE(P17CFG, GPIO_MUX_PG4);
/*PWM 5个通道*/
//IO配置为输出一定要放在设置完PWM之后,不然上电配置好IO的初始状态时候,运行到PWM_init这个函数的时候所有IO状态会变得不确定
GPIO_ENABLE_OUTPUT(P1TRIS,GPIO_PIN_3);
GPIO_ENABLE_OUTPUT(P1TRIS,GPIO_PIN_4);
GPIO_ENABLE_OUTPUT(P1TRIS,GPIO_PIN_5);
GPIO_ENABLE_OUTPUT(P1TRIS,GPIO_PIN_6);
GPIO_ENABLE_OUTPUT(P1TRIS,GPIO_PIN_7);
P13=0;P14=0;P15=0;P16=0;P17=0;
//开启EPWM
EPWM_Start(EPWM_CH_0_MSK|EPWM_CH_1_MSK|EPWM_CH_2_MSK|EPWM_CH_3_MSK|EPWM_CH_4_MSK);
}
Main函数
int main(void)
{
SYS_DisableLVD(); //关闭LVD 功能 降低睡眠功耗
WDT_DisableOverflowInt(); //关闭WDT中断
GPIO_Init();
GPIO_INT_Init(); //配置IO中断
TMR0_Config();
TMR1_Config();
ADC_Config();
PWM_Init();
IRQ_ALL_ENABLE(); //开启总中断
SYS_EnableWakeUp(); //使能STOP唤醒功能
while(1)
{
while(ADC_IS_BUSY); //必须等ADC转换完才能关闭ADCEN
ADC_Stop(); //关闭ADC
ADC_DisableLDO(); //关闭ADC的LDO
SYS_EnterStop(); //休眠
}
}
休眠的一些注意事项
首先,IO口肯定是要配置好进入睡眠前的状态。所有没用到的IO口,根据中微官方手册的建议是配置为输出模式,可以配置为输出高或低,不影响。
其次,ADC、ADC LDO、LSE、LVR还有PWM等外设模块,然后配置好IO中断(用于睡眠唤醒),调用库函数中的SYS_EnterStop(); 即可进入休眠模式。
进入休眠之后,唤醒MCU的时候有一个参数比较关键:
中微这个MCU比较有特色,唤醒之后还有一个稳定事件,过了稳定时间之后,才会把MCU唤醒并开始处理程序,这个时间在芯片设置里面调。
Keil里面打开魔术棒中的debug选项卡:
在右上角setting那里可以调整MCU的烧录配置:
下滑可以找到这个WAKEUP_WAITTIME,调整这个时间可以调整从睡眠状态唤醒之后开始执行语句的间隔时间,这个地方默认是1s,给人的感觉就是按了按键半天没反应,后来调整到50us之后,体感大大提升,基本上感觉不出来这个间隔时间。
最后
本项目移植过来就只需要用到上面这些模块,绝大多数代码都是参考中微官方提供的8S6990 Demo code来移植的,没什么技术含量,记录下来是为了方便日后使用,这篇博客就先分享到这。