三个按键中断:
void GPIO0_IRQHandler()
{
if(!(PA -> PIN & (1 << 0)))//判断按键SB1是否按下
{
PA_INT_DISABLE(0);//关闭PA10中断
Motor_Estop_flg = 1;//紧急停车标志位
TIMER0 -> TIM_CR1_b.CEN = 0;
GPIO_AF_SEL(DIGITAL, PA, 7, 0);// T0CH2
PA_OUT_DISABLE(7);
PA_INT_FLAG_CLR(0);//清除中断标志
PA_INT_ENABLE(0);//开启PA10中断
}
if(!(PA -> PIN & (1 << 10)))//判断按键SB3是否按下
{
PA_INT_DISABLE(10);//关闭PA10中断
Motor_R++;
PA_INT_FLAG_CLR(10);//清除中断标志
PA_INT_ENABLE(10);//开启PA10中断
}
if(!(PA -> PIN & (1 << 11)))//判断按键SB4是否按下
{
//蜂鸣器按键提示
PA_OUT_ENABLE(12);
PA_OUT_LOW(12);
delay_ms(200);
PA_OUT_HIGH(12);
PA_OUT_DISABLE(12);
SB4_Pressed_Flg ^= 1;//切换液晶或是矩阵键盘功能
if(SB4_Pressed_Flg)//模式选择位
{
PA -> OUTEN &= ~0X70;//PA输出失能 数码管位选端
NVIC_DisableIRQ(TIM6_T1_IRQn);
NVIC_EnableIRQ(TIM6_T0_IRQn);//选择矩阵键盘功能
}
else
{
PA -> OUTEN |= 0X70;//PA输出使能 数码管位选端
PB -> OUTEN |= 0XFF00;//PB输出使能
PB -> OUT &= 0X00FF;//数据清零
PA -> OUT |= 0X70;//位选置位 关断
NVIC_DisableIRQ(TIM6_T0_IRQn);
NVIC_EnableIRQ(TIM6_T1_IRQn);//选择数码管显示功能
}
PA_INT_FLAG_CLR(11);//清除中断标志
}
NVIC_ClearPendingIRQ(PA_IRQn);//清除中断
}
上述的代码洋洋洒洒,但是实际关键的就是几步:
1.设定PWM的频率
2.设定PWM波的占空比
3.开始输出PWM波
4.停止输出PWM
TIMER0 -> TIM_ARR = 500;// 自动重装载寄存器的值
printf("按键2启动 MOTOR RUNNINGn");
GPIO_AF_SEL(DIGITAL, PA, 7, 3);// T0CH2
TIMER0 -> TIM_CR1_b.CEN = 1;//计数器开始计数,当然PWM就可以输出了
我们简单粗暴一点:
1.设定PWM的频率
Tim0_Init_PWM(1000,196)不要动了,另外设定ARR,可以设定PWM频率,72Mhz/1000/ARR=....
TIMER0 -> TIM_ARR = 500;
.设定PWM波的占空比
设定CCRx可设定占空比,CCRx/(ARR+1)=......
TIMER0 -> TIM_CCR2 = PRD/4; // 占空比设置
3.开始输出PWM波
启动定时器可以开始输出PWM波
GPIO_AF_SEL(DIGITAL, PA, 7, 3);// T0CH2
TIMER0 -> TIM_CR1_b.CEN = 1;
4.停止输出PWM
TIMER0 -> TIM_CR1_b.CEN = 0;//计数器不可以计数了,当然就停止输出PWM波了
GPIO_AF_SEL(DIGITAL, PA, 7, 0);// PA7管脚不再是T0CH2的输出了
PA_OUT_DISABLE(7);
2采用专门的模块
LK32T102采用专用的 16 位时间基准计数器,有三个通道PWM波输出PWM0,PWM1和PWM2,每个通道为一个模块,每个通道又分为A,B两路。
每个 PWM 模块由 6 个子模块组成,不同的模块间结构完全相同,既可以独立运行,又可以通过时钟同步信号,组成 一个系统运行。
1. 时基子模块:
它是一个专用的 16 位计数器,以 PWM 时钟(TBCLK)频 率运行,该时钟是由系统时钟(SYSCLKOUT)(通过 TBCTL[CLKDIV])分频得到的。因此,通过设置时基计数器 的计数周期[TBPRD]即可确定 PWM 的周期和频率。
2. 计数比较子模块:
计数器比较子模块中有两个比较值寄存器 CMPA 和 CMPB,通过持续的与时间基准比较器的值进行比较来产 生比较事件。例如:TBCTR=CMPA,TBCTR=CMPB
3. 动作限定子模块:
动作限定子模块的主要功能是决定响应何种比较事件,做出何种动作,从而得到所需的 PWM 波形。
4. 死区生成子模块
为防止 PWM 某一通道的上下桥臂同时导通导致短路,需要在一个开关管彻底关断和同通道另一个开关管导通 之间加入“死区”。死区生成子模块的作用就在于此。
5. 故障保护子模块
故障保护子模块通过对故障信号的检测,判断是否发生了故障,从而控制 PWM 输出做出相应的动作。
6. 事件触发子模块
事件触发子模块通过管理时间基准子模块(TB)和计数比较子模块(CC)所产生的事件,产生一个中断到
CPU 或者一个 SOC 信号到 ADC。
实例:
产生一个频率为10KHz,负占空比为 10%的PWM波
1)管脚功能选择
void GPIO_Init(){
GPIO_AF_SEL(DIGITAL,PA,8,2); // PWM1A
// GPIO_AF_SEL(DIGITAL,PA,9,2); // PWM2B
// GPIO_AF_SEL(DIGITAL,PA,10,2); // PWM2A
// GPIO_AF_SEL(DIGITAL,PB,13,2); // PWM0B
// GPIO_AF_SEL(DIGITAL,PB,14,2); // PWM0A
// GPIO_AF_SEL(DIGITAL,PB,15,2); // PWM1B
//
....
}
管脚PA8的数字功能2(PWM1A)功能,具体设置哪一个管脚及哪一个通道,哪一路可查LK32T102编程手册。
2)设置PWM的频率
v
void PWM_Init(void){
PWM_CFG(3600, 0); // 72MHz下,10kHzPWM,0us死区
//PWM0 -> CMPA = 500; //PB14
PWM1 -> CMPA = 360; //PA8
//PWM2 -> CMPA = 1500; //PA10
PWM_START;
}
上述中1行调用了PWM_CFG(3600,0)对PWM进行配置,而4行设置了占空比。
因为采用增减计数的方式,计数脉冲也没有分频,所以,或者说PWM波的周期为0.1ms。
负占空比=360/3600=10%(?)或低电平时间为360*2/72=10us(?)
3)void PWM_CFG(uint32_t Period,uint32_t DB)关键代码分析
/************************************************************************
初始化PWM0-2,设置参数为:PWM半周期计数值、死区计数值
************************************************************************/
void PWM_CFG(uint32_t Period,uint32_t DB)
{
......
/******************************************************************************
PWM1
*******************************************************************************/
PWM1->TBPRD = Period; // 设置PWM1的半周期
PWM1->TBPHS = 0; // Set Phase register to zero
PWM1->TBCTL = 0;
PWM1_CTRMODE_UPDOWN; // Symmetrical mode CTRMODE
PWM1_PHASE_ENABLE; // Slave module PHSEN
PWM1_PRD_SHADOWON; // TB_SHADOW
PWM1->TBCTL_b.SYNCOSEL = SYNCOSEL_SYNC; // sync flow-through SYNCOSEL
PWM1->CMPCTL_b.SHDWAMODE = SHADOWMODE_ON; // CC_SHADOW
PWM1->CMPCTL_b.SHDWBMODE = SHADOWMODE_ON; // CC_SHADOW
PWM1->CMPCTL_b.LOADAMODE = CMP_LOAD_ZERO; // load on CTR=Zero
PWM1->CMPCTL_b.LOADBMODE = CMP_LOAD_ZERO; // load on CTR=Zero
PWM1->AQCTLA_b.CAU = AQ_CAU_CLR; // 当计数器等于主CMPA寄存器并且计数递增时动作:清除:使PWMxA输出低
PWM1->AQCTLA_b.CAD = AQ_CAD_SET; // 当计数器等于主CMPA寄存器并且计数递减时动作:置位:使PWMxA输出高
PWM1->AQCTLB_b.CAU = AQ_CAU_SET; // 当计数器等于主CMPB寄存器并且计数递增时动作:置位:使PWMxB输出高
PWM1->AQCTLB_b.CAD = AQ_CAD_CLR; // 当计数器等于主CMPB寄存器并且计数递减时动作:清除:使PWMxB输出低
PWM1->DBCTL_b.IN_MODE = DB_INMODE_PWMB_BOTH_EDGE; // PWMxBIN作为上升沿和下降沿延迟的输入源
PWM1->DBCTL_b.OUT_MODE = DB_OUTMODE_BOTH_ENABLE; // 死区对于PWMXA输入的上升沿延迟和PWMxB输出的下降沿延迟完全使能。
PWM1->DBCTL_b.POLSEL = DB_POLSEL_AHC; // 高有效互补(AHC)模式。PWMxB反相
PWM1->DBFED = DB; // 下降沿死区
PWM1->DBRED = DB; // 上升沿死区
....
}
需要注意的是这段代码 中还有很多的配置,如PWM触发中断等,如果不需要的话最好将其注释掉,因为频繁的中断发生有可能使得其他部分的代码没有机会运行。
三个按键中断:
void GPIO0_IRQHandler()
{
if(!(PA -> PIN & (1 << 0)))//判断按键SB1是否按下
{
PA_INT_DISABLE(0);//关闭PA10中断
Motor_Estop_flg = 1;//紧急停车标志位
TIMER0 -> TIM_CR1_b.CEN = 0;
GPIO_AF_SEL(DIGITAL, PA, 7, 0);// T0CH2
PA_OUT_DISABLE(7);
PA_INT_FLAG_CLR(0);//清除中断标志
PA_INT_ENABLE(0);//开启PA10中断
}
if(!(PA -> PIN & (1 << 10)))//判断按键SB3是否按下
{
PA_INT_DISABLE(10);//关闭PA10中断
Motor_R++;
PA_INT_FLAG_CLR(10);//清除中断标志
PA_INT_ENABLE(10);//开启PA10中断
}
if(!(PA -> PIN & (1 << 11)))//判断按键SB4是否按下
{
//蜂鸣器按键提示
PA_OUT_ENABLE(12);
PA_OUT_LOW(12);
delay_ms(200);
PA_OUT_HIGH(12);
PA_OUT_DISABLE(12);
SB4_Pressed_Flg ^= 1;//切换液晶或是矩阵键盘功能
if(SB4_Pressed_Flg)//模式选择位
{
PA -> OUTEN &= ~0X70;//PA输出失能 数码管位选端
NVIC_DisableIRQ(TIM6_T1_IRQn);
NVIC_EnableIRQ(TIM6_T0_IRQn);//选择矩阵键盘功能
}
else
{
PA -> OUTEN |= 0X70;//PA输出使能 数码管位选端
PB -> OUTEN |= 0XFF00;//PB输出使能
PB -> OUT &= 0X00FF;//数据清零
PA -> OUT |= 0X70;//位选置位 关断
NVIC_DisableIRQ(TIM6_T0_IRQn);
NVIC_EnableIRQ(TIM6_T1_IRQn);//选择数码管显示功能
}
PA_INT_FLAG_CLR(11);//清除中断标志
}
NVIC_ClearPendingIRQ(PA_IRQn);//清除中断
}
上述的代码洋洋洒洒,但是实际关键的就是几步:
1.设定PWM的频率
2.设定PWM波的占空比
3.开始输出PWM波
4.停止输出PWM
TIMER0 -> TIM_ARR = 500;// 自动重装载寄存器的值
printf("按键2启动 MOTOR RUNNINGn");
GPIO_AF_SEL(DIGITAL, PA, 7, 3);// T0CH2
TIMER0 -> TIM_CR1_b.CEN = 1;//计数器开始计数,当然PWM就可以输出了
我们简单粗暴一点:
1.设定PWM的频率
Tim0_Init_PWM(1000,196)不要动了,另外设定ARR,可以设定PWM频率,72Mhz/1000/ARR=....
TIMER0 -> TIM_ARR = 500;
.设定PWM波的占空比
设定CCRx可设定占空比,CCRx/(ARR+1)=......
TIMER0 -> TIM_CCR2 = PRD/4; // 占空比设置
3.开始输出PWM波
启动定时器可以开始输出PWM波
GPIO_AF_SEL(DIGITAL, PA, 7, 3);// T0CH2
TIMER0 -> TIM_CR1_b.CEN = 1;
4.停止输出PWM
TIMER0 -> TIM_CR1_b.CEN = 0;//计数器不可以计数了,当然就停止输出PWM波了
GPIO_AF_SEL(DIGITAL, PA, 7, 0);// PA7管脚不再是T0CH2的输出了
PA_OUT_DISABLE(7);
2采用专门的模块
LK32T102采用专用的 16 位时间基准计数器,有三个通道PWM波输出PWM0,PWM1和PWM2,每个通道为一个模块,每个通道又分为A,B两路。
每个 PWM 模块由 6 个子模块组成,不同的模块间结构完全相同,既可以独立运行,又可以通过时钟同步信号,组成 一个系统运行。
1. 时基子模块:
它是一个专用的 16 位计数器,以 PWM 时钟(TBCLK)频 率运行,该时钟是由系统时钟(SYSCLKOUT)(通过 TBCTL[CLKDIV])分频得到的。因此,通过设置时基计数器 的计数周期[TBPRD]即可确定 PWM 的周期和频率。
2. 计数比较子模块:
计数器比较子模块中有两个比较值寄存器 CMPA 和 CMPB,通过持续的与时间基准比较器的值进行比较来产 生比较事件。例如:TBCTR=CMPA,TBCTR=CMPB
3. 动作限定子模块:
动作限定子模块的主要功能是决定响应何种比较事件,做出何种动作,从而得到所需的 PWM 波形。
4. 死区生成子模块
为防止 PWM 某一通道的上下桥臂同时导通导致短路,需要在一个开关管彻底关断和同通道另一个开关管导通 之间加入“死区”。死区生成子模块的作用就在于此。
5. 故障保护子模块
故障保护子模块通过对故障信号的检测,判断是否发生了故障,从而控制 PWM 输出做出相应的动作。
6. 事件触发子模块
事件触发子模块通过管理时间基准子模块(TB)和计数比较子模块(CC)所产生的事件,产生一个中断到
CPU 或者一个 SOC 信号到 ADC。
实例:
产生一个频率为10KHz,负占空比为 10%的PWM波
1)管脚功能选择
void GPIO_Init(){
GPIO_AF_SEL(DIGITAL,PA,8,2); // PWM1A
// GPIO_AF_SEL(DIGITAL,PA,9,2); // PWM2B
// GPIO_AF_SEL(DIGITAL,PA,10,2); // PWM2A
// GPIO_AF_SEL(DIGITAL,PB,13,2); // PWM0B
// GPIO_AF_SEL(DIGITAL,PB,14,2); // PWM0A
// GPIO_AF_SEL(DIGITAL,PB,15,2); // PWM1B
//
....
}
管脚PA8的数字功能2(PWM1A)功能,具体设置哪一个管脚及哪一个通道,哪一路可查LK32T102编程手册。
2)设置PWM的频率
v
void PWM_Init(void){
PWM_CFG(3600, 0); // 72MHz下,10kHzPWM,0us死区
//PWM0 -> CMPA = 500; //PB14
PWM1 -> CMPA = 360; //PA8
//PWM2 -> CMPA = 1500; //PA10
PWM_START;
}
上述中1行调用了PWM_CFG(3600,0)对PWM进行配置,而4行设置了占空比。
因为采用增减计数的方式,计数脉冲也没有分频,所以,或者说PWM波的周期为0.1ms。
负占空比=360/3600=10%(?)或低电平时间为360*2/72=10us(?)
3)void PWM_CFG(uint32_t Period,uint32_t DB)关键代码分析
/************************************************************************
初始化PWM0-2,设置参数为:PWM半周期计数值、死区计数值
************************************************************************/
void PWM_CFG(uint32_t Period,uint32_t DB)
{
......
/******************************************************************************
PWM1
*******************************************************************************/
PWM1->TBPRD = Period; // 设置PWM1的半周期
PWM1->TBPHS = 0; // Set Phase register to zero
PWM1->TBCTL = 0;
PWM1_CTRMODE_UPDOWN; // Symmetrical mode CTRMODE
PWM1_PHASE_ENABLE; // Slave module PHSEN
PWM1_PRD_SHADOWON; // TB_SHADOW
PWM1->TBCTL_b.SYNCOSEL = SYNCOSEL_SYNC; // sync flow-through SYNCOSEL
PWM1->CMPCTL_b.SHDWAMODE = SHADOWMODE_ON; // CC_SHADOW
PWM1->CMPCTL_b.SHDWBMODE = SHADOWMODE_ON; // CC_SHADOW
PWM1->CMPCTL_b.LOADAMODE = CMP_LOAD_ZERO; // load on CTR=Zero
PWM1->CMPCTL_b.LOADBMODE = CMP_LOAD_ZERO; // load on CTR=Zero
PWM1->AQCTLA_b.CAU = AQ_CAU_CLR; // 当计数器等于主CMPA寄存器并且计数递增时动作:清除:使PWMxA输出低
PWM1->AQCTLA_b.CAD = AQ_CAD_SET; // 当计数器等于主CMPA寄存器并且计数递减时动作:置位:使PWMxA输出高
PWM1->AQCTLB_b.CAU = AQ_CAU_SET; // 当计数器等于主CMPB寄存器并且计数递增时动作:置位:使PWMxB输出高
PWM1->AQCTLB_b.CAD = AQ_CAD_CLR; // 当计数器等于主CMPB寄存器并且计数递减时动作:清除:使PWMxB输出低
PWM1->DBCTL_b.IN_MODE = DB_INMODE_PWMB_BOTH_EDGE; // PWMxBIN作为上升沿和下降沿延迟的输入源
PWM1->DBCTL_b.OUT_MODE = DB_OUTMODE_BOTH_ENABLE; // 死区对于PWMXA输入的上升沿延迟和PWMxB输出的下降沿延迟完全使能。
PWM1->DBCTL_b.POLSEL = DB_POLSEL_AHC; // 高有效互补(AHC)模式。PWMxB反相
PWM1->DBFED = DB; // 下降沿死区
PWM1->DBRED = DB; // 上升沿死区
....
}
需要注意的是这段代码 中还有很多的配置,如PWM触发中断等,如果不需要的话最好将其注释掉,因为频繁的中断发生有可能使得其他部分的代码没有机会运行。
举报