第六章作业
【6.3】
一基于 STM32F10x 微控制器的嵌入式应用系统使用的 GPIO 情况如图 6.24 所示,PA0 接 一按键,PC4 通过光耦驱动一个 VDD=24V DC 的继电器,继电器触点做为可控制的开关,连接到 220VAC 工作的喇叭,当 PC4 输出 0 逻辑时,光耦发光而使继电器得电闭合,喇叭发声。PD2 连接 LED 发光二极管,PD2 输出逻辑 0 时发光管亮。PB1 产生 200Hz~1KHz 方波,假设已经按照第 5 章的有关内容初始化 PA0 为输入高阻输入,PD2、PC4 和 PB1 为 2MHz 推挽输出。
(1)利用定时计数器 3(TIM3)定时 10ms,每当 10ms 中断一次,在中断服务程序中判断按键,当按键按下超过 0.5 秒小于 1 秒时称为短按,按下超过 3 秒时为长按。试用 C 语言写出定时器 3(TIM3)定时 10ms 的初始化函数; 当短按奇数次按键时,让 LED 发光,短按偶数按键时,让 LED 熄灭,长按偶数次按键时让喇叭发声报警,长按奇数次按键时停止发声,写入定时器 3(TIM3)的中断服务程序。
(2)利用PWM的捕获功能确定按键按下,通过PWM1(PB1:TIM3_CH4)输出200Hz~1KHz占空比为 50%的方波,由按键控制频率的改变,起始频率 200Hz,频率增加 1Hz。当达到 1KHz 时让 LED 亮,再按一次按键则回到 200Hz,当频率小于 950Hz 时让 LED 灭。试编程实现
解答:
(1)利用定时计数器 3(TIM3)定时 10ms,每当 10ms 中断一次,在中断服务程序中判断按键,当按键按下超过 0.5 秒小于 1 秒时称为短按,按下超过 3 秒时为长按。试用 C 语言写出定时器 3(TIM3)定时 10ms 的初始化函数; 当短按奇数次按键时,让 LED 发光,短按偶数按键时,让 LED 熄灭,长按偶数次按键时让喇叭发声报警,长按奇数次按键时停止发声,写入定时器 3(TIM3)的中断服务程序。
void NVIC_Configuration(void)//定时器中断配置
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0000);
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void TIM_Configuration(void) //配置定时器 3
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); ;/*使能 TIM3 对应时钟*/
TIM_TimeBaseStructure.TIM_Period = 10*10-1; /*定时 10ms */
TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock/10000-1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); /* 初始化 TIM3*/
/* TIM Interrupts enable */
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);/*使能 TIM3 更新中断*/
TIM_Cmd(TIM3, ENABLE);/*启动 TIM3 计数器*/
}
extern u32 TP1,TP2,Times;
int main(void)
{
SystemInit();
GPIO_Configuration();
TIM_Configuration(); /* 初始化 TIMx 定时器 */
NVIC_Configuration();
LCD_Init(); /* LCD 初始化 */
Welcome(); /* 显示主界面 */
LED1(1);LED2(1);LED3(1);LED4(1);
while(1)
{
if (Times>=300)
{
if (GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11)==0)
TP2++;
if (TP2&1)
{
GPIO_SetBits(GPIOC,GPIO_Pin_4);
Times=0;
}//停止报警
else
{
GPIO_ResetBits(GPIOC,GPIO_Pin_4);
Times=0;
}//报警
}
else if ((Times>=50)&&(Times<=150))
{
TP1++;
Delay_ms(10);
if (GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11)==1)
{
if (TP1&1) {GPIO_ResetBits(GPIOD,GPIO_Pin_2);
Times=0;
}//LED1 亮
else
{
GPIO_SetBits(GPIOD,GPIO_Pin_2);
Times=0;
}//LED1 灭
}
}
}
u32 Times=0,TP1=0,TP2;
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) /*判断是否是更新中断*/
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update); /*清除中断标志*/
if (GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11)==0)
Times++;//按下键计 10ms 倍数
}
}
(2)利用PWM的捕获功能确定按键按下,通过PWM1(PB1:TIM3_CH4)输出200Hz~1KHz占空比为 50%的方波,由按键控制频率的改变,起始频率 200Hz,频率增加 1Hz。当达到 1KHz 时让 LED 亮,再按一次按键则回到 200Hz,当频率小于 950Hz 时让 LED 灭。试编程实现
void PWM_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义一个 GPIO 结构体变量
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //PB1 TIM3 CH4 通道引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用输出推挽
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //配置端口速度为 50M
GPIO_Init(GPIOB, &GPIO_InitStructure); //将端口 GPIOD 进行初始化配置
}
void TIM2_Cap_Init(u16 arr,u16 psc)//TIM2 CH1 捕获方式 PA0
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_ICInitTypeDef TIM2_ICInitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); /*使能 TIM2 时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);/*使能 GPIOA 时钟*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; /*PA0 引脚 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; /*PA0 上拉输入 */
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA,GPIO_Pin_0); /*初始化 TIM2 输入捕获参数*/
TIM_TimeBaseStructure.Tim_Period = arr;
TIM_TimeBaseStructure.Tim_Prescalar = psc;
TIM_TimeBaseStructure.Tim_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.Tim_CounyerMode = TIM_ConnterMode_UP;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
TIM2_ICInitStructure.TIM_Channel = TIM_Channel_1; /*选择输入端 IC1 映射到 TI1 上*/
TIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling; /*下升沿捕获*/
TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; /*映射到 TI1 上*/
TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; /*配置输入不分频*/
TIM2_ICInitStructure.TIM_ICFilter = 0x00; /*配置输入不滤波*/
TIM_ICInit(TIM2, &TIM2_ICInitStructure); /*中断分组初始化*/
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; /*TIM2 中断*/
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; /*先占优先级 2 级*/
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; /*从优先级 0 级*/
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; /*IRQ 通道被使能*/
NVIC_Init(&NVIC_InitStructure);
TIM_ITConfig(TIM2, TIM_IT_CC1,ENABLE);/*允许 CC1IE 捕获中断*/
TIM_Cmd(TIM2,ENABLE ); /*使能定时器 2*/
}
void Init_PWM(uint16_t Dutyfactor)
{
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructureInit(&TIM_OCInitStructure);
TIM_OCInitstructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitstructure.TIM_Pulse = Dutyfactor;
TIM_OCInitstructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitstructure.TIM_OutPutState = TIM_OutPutState_Enable;
TIM_OC3Init(TIM2,&TIM_OCInit_OCInitStructure);
TIM_OC3PreloadConfig(TIM2,TIM_OCPreload_Enanble);
TIM_CtrlPWMOutputs(TIM2,Enable);
}
void change(u16 arr)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.Tim_Period = arr;
TIM_TimeBaseStructure.Tim_Prescalar = 0;
TIM_TimeBaseStructure.Tim_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.Tim_CounyerMode = TIM_ConnterMode_UP;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
}
//设预分频器值为0
void TIM2_IRQHandler(void)
{
u16 period,arr = 0;
if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET)
{
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
period = TIM_TimeBaseStructure.TIM_Period;
if((period<=359999)&(period>71999))//即200Hz-1KHz
{
arr = (72*10^6*(period+1))/(72*10^6+period+1)-1;
change(arr);
if(arr = 71999)
{
GPIOD->ODR&=~(1<<2);
}
}
else if(period == 71999)
{
arr = 35999;
change(arr);
}
if((arr<=359999)&(arr>75788))//即200Hz<= <950Hz
{
GPIOD->ODR |= (1<<2);
}
}
}
int main()
{
SystemInit();
PWM_GPIO_Init();
TIM2_Cap_Init(359999,0);
Init_PWM(360000*0.5);
while(1)
{
}
}