OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
12
返回列表 发新帖
楼主: 忘月19920216

从零开始学STM32(开贴记录我的学习历程)

[复制链接]

2

主题

60

帖子

0

精华

初级会员

Rank: 2

积分
153
金钱
153
注册时间
2016-2-25
在线时间
27 小时
 楼主| 发表于 2016-3-15 00:57:45 | 显示全部楼层
忘月19920216 发表于 2016-3-15 00:51
今天去逛街去了,很晚才回宿舍,不过独立看门狗的程序很快就编好了;
【2016-03-15】独立看门狗实验
独 ...

忘记上图了,补上;
独立看门狗相关库函数.png
串口调试助手.png
正点原子逻辑分析仪DL16劲爆上市
回复 支持 反对

使用道具 举报

2

主题

60

帖子

0

精华

初级会员

Rank: 2

积分
153
金钱
153
注册时间
2016-2-25
在线时间
27 小时
 楼主| 发表于 2016-3-16 00:23:25 | 显示全部楼层
窗口看门狗跟独立看门狗都是看门狗,程序的差别感觉不大;
【2016-03-15】窗口看门狗实验
独立看门狗配置过程:
①配置窗口看门狗时钟;
②配置分频值;
③配置窗口值;
④使能并装入计数器值;
⑤清除早期唤醒标志位;
⑥使能早期唤醒中断(当然还要配置嵌套向量中断控制器);
1、查看库函数指南、参考手册对应的内容,查看原子的例程并理解过程;
2、复制自己的外部中断工程(包含以前的LED,BEEP,KEY,USART,EXTI),写代码;
3、仿真调试,思考总结,记录发帖;

1、查看库函数指南、参考手册对应的内容,查看原子的例程并理解过程;
    独立看门狗配置过程:
    ①配置窗口看门狗时钟;
    ②配置分频值;
    ③配置窗口值;
    ④使能并装入计数器值;
    ⑤清除早期唤醒标志位;
    ⑥使能早期唤醒中断(当然还要配置嵌套向量中断控制器);

2、复制自己的外部中断工程(包含以前的LED,BEEP,KEY,USART,EXTI),写代码;
    从库函数使用手册复制库函数,写wwdg.c:
[mw_shl_code=applescript,true]#include "wwdg.h"
#include "led.h"
#include "usart.h"

void WWDG_Init(void)
{
   NVIC_InitTypeDef NVIC_InitStructure;
       
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);  // 使能窗口看门狗时钟

        WWDG_SetPrescaler(WWDG_Prescaler_8);   // 设置WWDG 计数器时钟为( PCLK/4096) /8
   WWDG_SetWindowValue(0x7f);   // 设置 WWDG 窗口值
   WWDG_Enable(0x7f);         // 使能 WWDG 并装入计数器值                  
   WWDG_ClearFlag(); // 清除早期唤醒中断标志位
   WWDG_EnableIT();  //使 能 WWDG 早期唤醒中断( EWI)
   
   NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;    // 选择WWDG中断
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;   // 抢占优先级3
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;         // 子优先级2
   NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
   NVIC_Init(&NVIC_InitStructure);
   
}

// 窗口看门狗中断服务函数
void WWDG_IRQHandler(void)
{
   WWDG_SetCounter(0x7f);          // 重装计数值
   WWDG_ClearFlag();          // 清除中断标志
   LED0=!LED0;                 // LED取反
   printf("窗口看门狗提前喂狗成功!\r\n");
   
}[/mw_shl_code]
    然后main.c里只要初始化就可以了:
[mw_shl_code=applescript,true]int main(void)
{       
   LED_Init();  
   BEEP_Init();
   KEY_Init();
   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
   uart_init(115200);
   delay_init();
   BOARD_EXTI_Init();
   WWDG_Init();
   
   // 初始化成功提示
   LED1 = 0;
   BEEP = 1;
   delay_ms(100);
//   LED0 = 0;
   LED1 = 1;
   BEEP = 0;
   printf("\r\nMCU启动!\r\n");
   
   while(1)
        {
      LED1 = 1;
   }
}[/mw_shl_code]
    在外部中断的中断服务函数里加一个延时,并把外部中断的优先级设为比窗口看门狗早期唤醒中断优先级高,这样就可以利用触发外部中断来阻止喂狗,就可以观察到窗口看门狗对系统进行复位:
[mw_shl_code=applescript,true]// 外部中断3中断服务函数
// KEY1 -> PE3 -> EXTI3;
void EXTI3_IRQHandler(void)
{
   delay_ms(5);
   
   if(KEY1 == 0)
   {
      printf("\r\n进入中断,阻止喂狗!\r\n");
      delay_ms(500);
   }
   else
      ;
   EXTI_ClearITPendingBit(EXTI_Line3);  //清除LINE3上的中断标志
}

// 外部中断4中断服务函数
// KEY0 -> PE4 -> EXTI4;
void EXTI4_IRQHandler(void)
{
   delay_ms(5);
   
   if(KEY0 == 0)
   {
      printf("\r\n进入中断,阻止喂狗!\r\n");
      delay_ms(500);
   }
   else
      ;
   
   EXTI_ClearITPendingBit(EXTI_Line4);  //清除LINE4上的中断标志
}
[/mw_shl_code]
3、仿真调试,思考总结,记录发帖;

    实验一次通过,程序实现了自己预想的功能,接下来再学习定时器后,对STM32的基本使用应该就顺手点了;



串口助手.png
回复 支持 反对

使用道具 举报

2

主题

60

帖子

0

精华

初级会员

Rank: 2

积分
153
金钱
153
注册时间
2016-2-25
在线时间
27 小时
 楼主| 发表于 2016-3-16 00:27:47 | 显示全部楼层
忘月19920216 发表于 2016-3-16 00:23
窗口看门狗跟独立看门狗都是看门狗,程序的差别感觉不大;
【2016-03-15】窗口看门狗实验
独立看门狗配置 ...

窗口看门狗……复制过来的成独立看门狗了
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
10
金钱
10
注册时间
2016-3-16
在线时间
3 小时
发表于 2016-3-16 16:51:08 | 显示全部楼层
学习了,非常感谢分享!!!
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
5
金钱
5
注册时间
2016-1-18
在线时间
1 小时
发表于 2016-3-16 17:51:58 | 显示全部楼层
一起学习~
回复 支持 反对

使用道具 举报

0

主题

8

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1016
金钱
1016
注册时间
2016-2-26
在线时间
76 小时
发表于 2016-3-16 18:06:30 | 显示全部楼层
顶一下!一直想学,可是一直还没什么行动,开发板在角落里躺着睡觉呢!
回复 支持 反对

使用道具 举报

2

主题

60

帖子

0

精华

初级会员

Rank: 2

积分
153
金钱
153
注册时间
2016-2-25
在线时间
27 小时
 楼主| 发表于 2016-3-17 00:44:33 | 显示全部楼层
【2016-03-16】定时器3中断实验
定时器基本配置过程:
①配置时钟;
②配置重装值;
③配置分频值;
④配置时钟分割值;
⑤配置计数模式;
⑥开启定时器;
⑦使能中断(当然还要去配置嵌套向量中断控制器);

1、查看库函数指南、参考手册对应的内容,查看原子的例程并理解过程;
2、复制自己的外部中断工程(包含以前的LED,BEEP,KEY,USART,EXTI),写代码;
3、仿真调试,思考总结,记录发帖;

1、查看库函数指南、参考手册对应的内容,查看原子的例程并理解过程;
定时器基本配置过程:
    ①配置时钟;
    ②配置重装值;
    ③配置分频值;
    ④配置时钟分割值;
    ⑤配置计数模式;
    ⑥开启定时器;
    ⑦使能中断(当然还要去配置嵌套向量中断控制器,编写中断服务函数);
注意:如果APB的预分频系数不是1,定时器的时钟频率被设为与其相连的APB总线频率的2倍,例如如本实验;
2、复制自己的外部中断工程(包含以前的LED,BEEP,KEY,USART,EXTI),写代码;
从库函数指南里复制库函数出来,编写timer.c,中断向量配置直接从EXTI的程序里复制过来改:
[mw_shl_code=applescript,true]void TIMER3_Init(void)
{
   TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
       
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);  // 使能TIM3时钟
       
   TIM_TimeBaseStructure.TIM_Period = 999;   // 计1000次,500ms
   TIM_TimeBaseStructure.TIM_Prescaler = 35999;   // 需要得到准确500us的话还是应该写35999
   TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;  // TDTS = Tck_tim
   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
   TIM_TimeBaseInit(TIM3, & TIM_TimeBaseStructure);
       
        TIM_Cmd(TIM3, ENABLE);  // 开启定时器3
   TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE );  // 使能TIM3更新中断
       
   //中断优先级NVIC设置
        NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  // TIM3中断
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;  // 先占优先级3
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  // 从优先级3
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
          
}

// 定时器3中断服务程序
void TIM3_IRQHandler(void)   // TIM3中断
{
        if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)  // 判断是否是更新中断
                {
                   LED0=!LED0;
         printf("\r\n定时器更新,触发定时器更新中断\r\n");
                   TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  // 清除更新中断标志
                }
}[/mw_shl_code]
然后为它写一个timer.h:
[mw_shl_code=applescript,true]#ifndef __TIMER_H
#define __TIMER_H         
#include "sys.h"

void TIMER3_Init(void);

#endif
[/mw_shl_code]
然后在main.c里初始化定时器:
[mw_shl_code=applescript,true]int main(void)
{       
   LED_Init();  
   BEEP_Init();
   KEY_Init();
   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
   uart_init(115200);
   delay_init();
   BOARD_EXTI_Init();
   TIMER3_Init();
   
   // 初始化成功提示
   LED1 = 0;
   BEEP = 1;
   delay_ms(100);
//   LED0 = 0;
   LED1 = 1;
   BEEP = 0;
   printf("\r\n\r\n\r\n请按键触发中断\r\n");
   
   while(1)
        {
      LED0 = 1;
   }
}[/mw_shl_code]
3、仿真调试,思考总结,记录发帖;
调试的时候,灯闪了,就是闪得有点快,本来是想着一秒闪一次的,但是怎么着也感觉那个一秒起码也闪了两次,以为自己还有哪里没注意到,再看了下文档也没看出个什么,只能把定时时间设长一些,翻个倍,发现是一秒闪一次了,但是亮了马上灭,占空比并不是50%的,这时候才想起,在main函数的循环里,写了一条“LED0 = 1;”在,这样看来,程序是正常的,只是我想得不正常



向上计数模式.png
TIM相关标志.png
定时器时钟频率分配.png
串口调试助手.png
回复 支持 反对

使用道具 举报

2

主题

60

帖子

0

精华

初级会员

Rank: 2

积分
153
金钱
153
注册时间
2016-2-25
在线时间
27 小时
 楼主| 发表于 2016-3-17 00:45:41 | 显示全部楼层
pcwww 发表于 2016-3-16 16:51
学习了,非常感谢分享!!!

一起学习,相互学习~
回复 支持 反对

使用道具 举报

2

主题

60

帖子

0

精华

初级会员

Rank: 2

积分
153
金钱
153
注册时间
2016-2-25
在线时间
27 小时
 楼主| 发表于 2016-3-17 00:45:58 | 显示全部楼层

共同努力~
回复 支持 反对

使用道具 举报

2

主题

60

帖子

0

精华

初级会员

Rank: 2

积分
153
金钱
153
注册时间
2016-2-25
在线时间
27 小时
 楼主| 发表于 2016-3-17 00:48:29 | 显示全部楼层
求索者 发表于 2016-3-16 18:06
顶一下!一直想学,可是一直还没什么行动,开发板在角落里躺着睡觉呢!

基本的使用,学的话时间要得不是很多,就把板子上有的东西能跑的东西用一遍,一些深层次的应用就到具体什么项目需要的时候再深入学习呗~
回复 支持 反对

使用道具 举报

2

主题

60

帖子

0

精华

初级会员

Rank: 2

积分
153
金钱
153
注册时间
2016-2-25
在线时间
27 小时
 楼主| 发表于 2016-3-17 00:49:05 | 显示全部楼层
大好大 发表于 2016-3-13 15:06
加油,加油,同为初学,像楼主学习!!

谢谢,一起加油!
回复 支持 反对

使用道具 举报

2

主题

60

帖子

0

精华

初级会员

Rank: 2

积分
153
金钱
153
注册时间
2016-2-25
在线时间
27 小时
 楼主| 发表于 2016-3-18 00:59:24 | 显示全部楼层
昨天配完定时器就想着马上就能配置输出PWM了,结果搞到现在还不是很懂
【2016-03-17】定时器输出PWM
定时器输出PWM基本配置过程:
①使能各时钟;
②配置IO口;
③配置定时器基本参数;
④配置定时器比较通道;

1、查看库函数指南、参考手册对应的内容,查看原子的例程并理解过程;
2、复制昨天的TIM3工程(包含以前的LED,BEEP,KEY,USART,EXTI,TIM3),写代码;

3、仿真调试,思考总结,记录发帖;


1、查看库函数指南、参考手册对应的内容,查看原子的例程并理解过程;
    定时器输出PWM基本配置过程:
    ①使能各时钟;
    ②配置IO口;
    ③配置定时器基本参数;
    ④配置定时器比较通道;

2、复制昨天的TIM3工程(包含以前的LED,BEEP,KEY,USART,EXTI,TIM3),写代码;
    先在昨天timer.c里面修改,增加比较输出功能(我下的这个库函数指南在这里跟实际库差别有些大,还有好多没有理解):
[mw_shl_code=applescript,true]void TIMER3_PWM_CH2_Init(void)
{
   GPIO_InitTypeDef GPIO_InitStructure;
   TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
   TIM_OCInitTypeDef TIM_OCInitStructure;
          
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);  // 使能TIM3时钟
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  // 使能GPIOB和AFIO复用功能时钟
   
   GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); // TIM3复用功能部分映射 TIM3_CH2 -> PB5
   
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
   GPIO_Init(GPIOB,&GPIO_InitStructure);
   
   TIM_TimeBaseStructure.TIM_Period = 899;   // 计900次
   TIM_TimeBaseStructure.TIM_Prescaler = 0;   // 不分频
   TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;  // TDTS = Tck_tim
   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
   TIM_TimeBaseInit(TIM3, & TIM_TimeBaseStructure);
   
   // 初始化TIM3 CH2 PWM模式         
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; // TIM脉冲宽度调制模式2
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 比较输出使能
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // TIM输出比较极性高
        TIM_OC2Init(TIM3, &TIM_OCInitStructure);  // 初始化TIM3的OC2
   
   TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  // 使能TIM3在CCR2上的预装载寄存器
        TIM_Cmd(TIM3, ENABLE);  // 开启定时器3
}[/mw_shl_code]
    再在main.c里面不停更改[size=14.6667px]捕获/比较2寄存器值以改变输出脉宽:
[mw_shl_code=applescript,true]int main(void)
{       
   u8 dir = 1;
   u8 pwm_value = 0;
   
//   LED_Init();  
   BEEP_Init();
   KEY_Init();
   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
   uart_init(115200);
   delay_init();
   BOARD_EXTI_Init();
//   TIMER3_Init();
   TIMER3_PWM_CH2_Init();
   
   // 初始化成功提示
//   LED1 = 0;
   BEEP = 1;
   delay_ms(100);
//   LED0 = 0;
//   LED1 = 1;
   BEEP = 0;
   printf("\r\n\r\n\r\n请按键触发中断\r\n");
   
   while(1)
        {
      delay_ms(10);         
                if(dir)
         pwm_value++;
                else
         pwm_value--;

                if(pwm_value==255)
         dir = 0;
                if(pwm_value==0)
         dir = 1;       
      
                TIM_SetCompare2(TIM3,pwm_value);
   }
}[/mw_shl_code]
3、仿真调试,思考总结,记录发帖;

    现在能把灯点亮了,亮度能变化,可以仿照着例程使用定时器的[size=14.6667px]捕获/比较功能了,理解也能理解了,就是这里的库函数跟库函数指南不对应,应该是版本的差别,找东西比较难找;
[size=14.6667px]


TIM3复用功能部分重映射.png

这里跟实际库函数不对应

这里跟实际库函数不对应
设置比较捕获2寄存器.png
回复 支持 反对

使用道具 举报

2

主题

60

帖子

0

精华

初级会员

Rank: 2

积分
153
金钱
153
注册时间
2016-2-25
在线时间
27 小时
 楼主| 发表于 2016-3-25 01:32:07 | 显示全部楼层
周末一直在外面,后面又去长沙参加学习,这几天没有编过程,但是看了好多视频和资料,感觉自己可以不用看资料看例程就完成定时器捕获了,结果今晚试了下,没成功,但是离成功也不远了。
【2016-03-24】定时器捕获实验
定时器捕获初始化配置:
①使能各时钟;
②配置IO口;
③配置定时器基本参数;
④配置定时器捕获通道;

⑤配置定时器捕获中断(当然还要写中断服务函数);
本次遇到的问题:
①忘记配置NVIC;
②给变量或上一个0x40之后还一直去判断它是否小于0x3f;


1、复制之前的TIM3_PWM工程(包含以前的LED,BEEP,KEY,USART,EXTI,TIM3_PWM),写代码;
2、仿真调试,思考总结,记录发帖;



1、复制之前的TIM3_PWM工程(包含以前的LED,BEEP,KEY,USART,EXTI,TIM3_PWM),写代码;
    从定时器3的初始化函数里复制一些内容,完成对TIM5的基本配置,再加上对捕获通道1的配置,完成timer.c:
[mw_shl_code=applescript,true]void TIMER5_IC_CH1_Init(void)
{
   GPIO_InitTypeDef GPIO_InitStructure;
   TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
   TIM_ICInitTypeDef TIM_ICInitTypeStructue;
   NVIC_InitTypeDef NVIC_InitStructure;
          
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);  // 使能TIM5时钟
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  // 使能GPIOA时钟
   
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
//   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; // 下拉输入
   GPIO_Init(GPIOA,&GPIO_InitStructure);
   
   TIM_TimeBaseStructure.TIM_Period = 0xffff;   // 计65536次
   TIM_TimeBaseStructure.TIM_Prescaler = 71;   // 72分频,1us
   TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;  // TDTS = Tck_tim
   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数模式
   TIM_TimeBaseInit(TIM5, & TIM_TimeBaseStructure);
   
   // 初始化TIM5 CH1捕获模式         
        TIM_ICInitTypeStructue.TIM_Channel = TIM_Channel_1;   // 通道1
   TIM_ICInitTypeStructue.TIM_ICPolarity = TIM_ICPolarity_Rising; // 上升沿捕获
   TIM_ICInitTypeStructue.TIM_ICSelection = TIM_ICSelection_DirectTI;   // 连接到IC1
   TIM_ICInitTypeStructue.TIM_ICPrescaler = TIM_ICPSC_DIV1; // 不分频
   TIM_ICInitTypeStructue.TIM_ICFilter = 0x0;  // 不滤波
        TIM_ICInit(TIM5, &TIM_ICInitTypeStructue);  // 初始化TIM5的IC1
   
   //中断优先级NVIC设置
        NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;  // TIM3中断
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;  // 先占优先级3
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  // 从优先级3
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
   
   TIM_ITConfig(TIM5, TIM_IT_Update | TIM_IT_CC1,ENABLE);  // 使能中断
        TIM_Cmd(TIM5, ENABLE);  // 开启定时器5
}

// 定时器5中断服务程序
u8    TIM5CH1_capture_state = 0; // 捕获状态
u16   TIM5CH1_capture_value = 0; // 捕获值
void TIM5_IRQHandler(void)
{
   if((TIM5CH1_capture_state & 0x80) == 0)  // 还未成功捕获
   {
      if(TIM_GetITStatus(TIM5,TIM_IT_CC1)) // 如果是捕获中断
      {
         if((TIM5CH1_capture_state & 0x40) == 0)   // 如果没有捕获过上升沿(本次即为上升沿)
         {
            TIM_SetCounter(TIM5,0); // 重装0
            TIM5CH1_capture_state = 0x40;
            TIM5CH1_capture_value = 0x0;
            TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); // 改为下降沿捕获
            printf("\r\n按键开始\r\n");
         }            
         else if(TIM5CH1_capture_state & 0x40)  // 如果已经捕获过上升沿(本次即为下降沿)
         {
            TIM5CH1_capture_value = TIM_GetCapture1(TIM5);  // 读定时器计数值
            TIM5CH1_capture_state |= 0x80;   // 表明已完成一次捕获
            TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); // 改为上升沿捕获   
            printf("\r\n按键释放报告:\r\n");      
            printf("\r\nTIM5CH1_capture_state & 0x3f = %d\r\n",TIM5CH1_capture_state & 0x3f);   
            printf("\r\nTIM5CH1_capture_value = %d\r\n",TIM5CH1_capture_value);                  
         }
         else ;
      }
      else if(TIM_GetITStatus(TIM5,TIM_IT_Update) && (TIM5CH1_capture_state & 0x40)) // 如果是更新中断,且已开始为高电平计时
      {
         if((TIM5CH1_capture_state & 0x3f) < 0x3f) // 如果没超过计数能力
         {
            TIM5CH1_capture_state ++;
            printf("\r\nTIM5CH1_capture_state & 0x3f = %d\r\n",TIM5CH1_capture_state & 0x3f);  
         }
         else
         {
            printf("\r\n超过计数能力,请放开那个按键!\r\n");
         }
      }
      else ;
   }
   else ;
   
  TIM_ClearITPendingBit(TIM5,TIM_IT_Update | TIM_IT_CC1);   // 清除中断标志
   
}


[/mw_shl_code]
    然后在main.c里对计数值进行计算:
[mw_shl_code=applescript,true]int main(void)
{       
   u8 dir = 1;
   u8 pwm_value = 0;
   u32 key_up_value = 0;
   
//   LED_Init();  
   BEEP_Init();
   KEY_Init();
   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
   uart_init(115200);
   delay_init();
   BOARD_EXTI_Init();
//   TIMER3_Init();
   TIMER3_PWM_CH2_Init();
   TIMER5_IC_CH1_Init();
   
   // 初始化成功提示
//   LED1 = 0;
   BEEP = 1;
   delay_ms(100);
//   LED0 = 0;
//   LED1 = 1;
   BEEP = 0;
   printf("\r\n\r\n\r\n请按键\r\n");
   
   while(1)
        {
      delay_ms(10);         
                if(dir)
         pwm_value++;
                else
         pwm_value--;

                if(pwm_value==255)
         dir = 0;
                if(pwm_value==0)
         dir = 1;       
      
                TIM_SetCompare2(TIM3,pwm_value);
      
      if(TIM5CH1_capture_state & 0x80) // 如果捕获完成了
      {  
         key_up_value = TIM5CH1_capture_state & 0x3f;
         key_up_value *= 65536;
         key_up_value += TIM5CH1_capture_value;
         printf("\r\n计算结果:\r\n");
         printf("\r\nkey_up_time = %d   us\r\n",key_up_value);   // 打印高电平值
         
         TIM5CH1_capture_state = 0; // 开启下一次捕获
      }
   }
}
[/mw_shl_code]
2、仿真调试,思考总结,记录发帖;

程序实现了自己预想的功能,不过花了很多时间修改才完成的。这次试了下不看资料也不看例程直接写程序,还是经验欠缺,还要慢慢积累。



串口助手.png
回复 支持 反对

使用道具 举报

0

主题

3

帖子

0

精华

新手上路

积分
34
金钱
34
注册时间
2016-3-15
在线时间
11 小时
发表于 2016-3-31 10:27:47 | 显示全部楼层
大兄弟弃楼了啊!
回复 支持 反对

使用道具 举报

1

主题

5

帖子

0

精华

初级会员

Rank: 2

积分
57
金钱
57
注册时间
2016-3-7
在线时间
18 小时
发表于 2016-4-2 15:49:21 来自手机 | 显示全部楼层
怎么没有然后了?
回复 支持 反对

使用道具 举报

22

主题

147

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3983
金钱
3983
注册时间
2015-4-18
在线时间
403 小时
发表于 2016-4-3 07:54:25 | 显示全部楼层
支持一个。。。
回复 支持 反对

使用道具 举报

2

主题

60

帖子

0

精华

初级会员

Rank: 2

积分
153
金钱
153
注册时间
2016-2-25
在线时间
27 小时
 楼主| 发表于 2016-6-21 01:14:28 | 显示全部楼层
由于某些不可抗力,我暂停了STM32学习,一转眼3个月过去了,一直惦记着这个事,今天又可以开始学习了,之前学到定时器捕获,今天还是先学一学定时器,做一做电容触摸按键,进入状态吧。
【2016-06-20】触摸按键实验
电容触摸按键复位:
①IO口设为推挽输出;
②IO输出0,并延时一定时间以放电;
③TIM5计数寄存器清零,清除中断标志;
④IO口设为模拟输入(以等待捕获到上升沿);
获取充电时间:
①等待捕获到上升沿;
②返回捕获寄存器值;
电容触摸按键获初始化配置:
①初始化定时器通道(包括IO口配置,定时器基本配置,定时器捕获配置);
②连续读10次;
③取中间6次求平均值作为没有按下时的充电时间计数值;
电容触摸按键按下检测:
①采样三次,取最大值;
②跟没按下时的计数值比较判断是否按下;

1、复制之前的TIM3_PWM工程(包含以前的LED,BEEP,USART),复制原子官方历程的配置函数,写代码;
2、仿真调试,思考总结,记录发帖;

1、复制之前的TIM3_PWM工程(包含以前的LED,BEEP,USART),复制原子官方历程的配置函数,写代码;
    仔细了解之后,感觉这个电容触摸按键很有意思,根据有没有按下时电容的差别,来判断是否按下,STM32使用定时器对电容的充电时间进行计数,通过比较充电时间计数值,STM32就能判断是否有键按下了;
    从原子给的历程里复制函数,写好tpad.c:
[mw_shl_code=applescript,true]/**
  ******************************************************************************
  * @file    tpad.c
  * @author  YangJie
  * @version V0.0
  * @date    2016-6-20
  * @brief            
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "tpad.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_rcc.h"
#include "usart.h"
#include "delay.h"

/* Private functions ---------------------------------------------------------*/
vu16 tpad_default_val = 0;  // 空载的时候(没有手按下),计数次数
/**
  * @brief  TIM5_CC_Init
  * @param  None
  * @retval None
  * @brief  配置TIM5_CH2输入捕获模式
  */
void TIM5_CC_Init(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_ICInitTypeDef  TIM5_ICInitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);    // 使能TIM5时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   // 使能PA端口时钟
    // 配置GPIO
    // TPAD-> STM_ADC -> PA1 ;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;     // 设置为浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    //初始化TIM5_CH2  
    TIM_TimeBaseStructure.TIM_Period = 0xffff;  // 计到最大的次数
    TIM_TimeBaseStructure.TIM_Prescaler = 5;    // 5分频
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;         // TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;     // 向上计数模式
    TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
   
    TIM5_ICInitStructure.TIM_Channel = TIM_Channel_2;
    TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;        // 上升沿捕获
    TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;    // 连接到IC1
    TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;      // 不分频
    TIM5_ICInitStructure.TIM_ICFilter = 0x03;   // 0011 8个定时器时钟周期滤波
    TIM_ICInit(TIM5, &TIM5_ICInitStructure);

    TIM_Cmd(TIM5, ENABLE);  // 开启定时器5
          
}

/* Private functions ---------------------------------------------------------*/
/**
  * @brief  TPAD_Reset
  * @param  None
  * @retval None
  * @brief  复位一次TPAD
  */
void TPAD_Reset(void)
{
          GPIO_InitTypeDef  GPIO_InitStructure;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   // 使能PA端口时钟
       
        //PA1设为推挽使出
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;        // 设为推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);
        GPIO_ResetBits(GPIOA,GPIO_Pin_1);

        delay_ms(5);

        TIM_SetCounter(TIM5,0);                // 计数器清零
        TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update);  // 清除中断标志
        //PA1设为浮空输入
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;            // 设为浮空输入
        GPIO_Init(GPIOA, &GPIO_InitStructure);
   
}

/* Private functions ---------------------------------------------------------*/
/**
  * @brief  TPAD_Get_Val
  * @param  None
  * @retval TIM_GetCapture2(TIM5)
  * @brief  获取捕获值,若没捕获到,则返回最大值
  */
u16 TPAD_Get_Val(void)
{                                  
        TPAD_Reset();
        while(TIM_GetFlagStatus(TIM5, TIM_IT_CC2) == RESET) // 等待捕获上升沿
        {
                if(TIM_GetCounter(TIM5)>(0xffff-500))
            return TIM_GetCounter(TIM5);// 超时了,直接返回CNT的值
        else
            ;
        }       
        return TIM_GetCapture2(TIM5);       
   
}


/* Private functions ---------------------------------------------------------*/
/**
  * @brief  TPAD_Init
  * @param  None
  * @retval 0/1  0:正常  1:不正常
  * @brief  初始化TPAD
  */
u8 TPAD_Init(void)
{
        u16 buf[10];
        u16 temp;
        u8 j,i;
        TIM5_CC_Init();    //
        for(i=0;i<10;i++)       // 连续读取10次
        {                                 
                buf=TPAD_Get_Val();
                delay_ms(10);            
        }                                    
        for(i=0;i<9;i++)    // 排序
        {
                for(j=i+1;j<10;j++)
                {
                        if(buf>buf[j])   // 升序排列
                        {
                                temp=buf;
                                buf=buf[j];
                                buf[j]=temp;
                        }
                }
        }
        temp=0;
        for(i=2;i<8;i++)   // 取中间的6个数据进行平均
        temp+=buf;
    tpad_default_val=temp/6;
        printf("tpad_default_val:%d\r\n",tpad_default_val);       
        if(tpad_default_val>(0xffff/2))
        return 1;//初始化遇到超过最大计数0xfff/2的数值,不正常
    else
        ;
        return 0;                                                                           
}

/* Private functions ---------------------------------------------------------*/
/**
  * @brief  TPAD_Get_MaxVal
  * @param  n
  * @retval res
  * @brief  读取n次,取最大值
  */
u16 TPAD_Get_MaxVal(u8 n)
{
        u16 temp=0;
        u16 res=0;
        while(n--)
        {
                temp=TPAD_Get_Val();    // 得到一次值
                if(temp>res)
            res=temp;
        else
            ;
        };
        return res;
}  

/* Private functions ---------------------------------------------------------*/
/**
  * @brief  TPAD_Scan
  * @param  mode 0:不支持连按,1:支持连按
  * @retval res 0:有键按下,1:无键按下
  * @brief  读取n次,取最大值
  */
u8 TPAD_Scan(u8 mode)
{
        static u8 keyen=0;        // 0,可以开始检测;>0,还不能开始检测         
        u8 res=0;
        u8 sample=3;                // 默认采样次数为3次         
        u16 rval;
        if(mode)
        {
                sample=6;                // 支持连按的时候,设置采样次数为6次
                keyen=0;                // 支持连按          
        }
        rval=TPAD_Get_MaxVal(sample);
        if(rval>(tpad_default_val + 100))   // 大于tpad_default_val+TPAD_GATE_VAL,有效
        {                                                         
                if(keyen==0)res=1;                // keyen==0,有效
                printf("%4d--%4d\r\n",tpad_default_val,rval);                                                                           
                keyen=3;                                // 至少要再过3次之后才能按键有效   
        }
        if(keyen)keyen--;                                                                                                                                                         
        return res;
}       
[/mw_shl_code]
然后为其写 一个tpad.h:
[mw_shl_code=applescript,true]/**
  ******************************************************************************
  * @file    tpad.h
  * @author  YangJie
  * @version V0.0
  * @date    2016-6-20
  * @brief            
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __TIM5_TPAD_H
#define __TIM5_TPAD_H

/* Includes ------------------------------------------------------------------*/
#include "sys.h"

/* Exported functions ------------------------------------------------------- */
u8 TPAD_Init(void);
u8 TPAD_Scan(u8 mode);
   
#endif
[/mw_shl_code]
然后在main.c里不断检测按键是否按下:
[mw_shl_code=applescript,true]int main(void)
{       
    u8 i = 1;
   
    LED_Init();  
//   BEEP_Init();
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    uart_init(115200);
    delay_init();
    TPAD_Init();
   
   // 初始化成功提示
    LED1 = 0;
//   BEEP = 1;
    delay_ms(100);
    LED0 = 0;
    LED1 = 1;
//   BEEP = 0;
    printf("\r\n\r\n\r\n请按键\r\n");
   
    while(1)
    {
        if(TPAD_Scan(0))        // 成功捕获到了一次上升沿(此函数执行时间至少15ms)
                {
                        LED1=!LED1;                // LED1取反
                }
        else
        {}
        
                if(i++ == 50)                 
                {
                        i = 0;
                        LED0 = !LED0;   // LED0取反,提示程序正在运行
            printf("\r\n请按键\r\n");
                }
        else
        {}
            
    }
}
[/mw_shl_code]
2、仿真调试,思考总结,记录发帖;
程序能按照预想的样子工作,很神奇,手碰一下就能识别到;
这次是先看了视频再来写程序的,程序内容在看视频的时候理解了一遍,里面的配置函数等,就直接复制了……


TPAD接到STM32的定时器5通道2的引脚.png
串口调试截图.jpg
回复 支持 反对

使用道具 举报

3

主题

7

帖子

0

精华

新手上路

积分
40
金钱
40
注册时间
2016-6-4
在线时间
5 小时
发表于 2016-6-22 11:57:29 | 显示全部楼层
it8345 发表于 2016-3-6 15:29
加油,帮顶,跟楼主差不多,我基本外设差不多都会用了,只是熟练度还差点,现在一边复习一边看UCOS,已经大 ...

马蛋我研一才开始学,
回复 支持 反对

使用道具 举报

0

主题

32

帖子

0

精华

初级会员

Rank: 2

积分
171
金钱
171
注册时间
2016-3-16
在线时间
48 小时
发表于 2016-6-22 14:37:16 | 显示全部楼层
顶楼主 支持一个
回复 支持 反对

使用道具 举报

1

主题

9

帖子

0

精华

新手上路

积分
39
金钱
39
注册时间
2016-7-27
在线时间
7 小时
发表于 2016-7-29 21:44:46 | 显示全部楼层
敢问楼主几年级
回复 支持 反对

使用道具 举报

1

主题

9

帖子

0

精华

新手上路

积分
39
金钱
39
注册时间
2016-7-27
在线时间
7 小时
发表于 2016-7-30 14:59:43 | 显示全部楼层
仔细看了一下楼主的学习过程,收益颇大,同时发现竟然还有固件库的手册,弄得我只能从教程里面一点点学,一个月了才了解用一点外设,有好多理论知识都不懂,一直在看底层的寄存器,不知道51还没会用就接触arm是福还是祸。。。多说都是泪
回复 支持 反对

使用道具 举报

0

主题

5

帖子

0

精华

初级会员

Rank: 2

积分
72
金钱
72
注册时间
2017-3-20
在线时间
16 小时
发表于 2017-4-27 19:40:25 | 显示全部楼层
先谢谢你写的这篇帖子,是不经意间找问题找到的。但你解决了我最近一直存在的问题,不会活学活用我,现在我准备把前面学过的自己整合一遍,做出自己的程序来。谢谢你
回复 支持 反对

使用道具 举报

15

主题

83

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
211
金钱
211
注册时间
2016-9-27
在线时间
42 小时
发表于 2017-4-27 21:11:47 | 显示全部楼层
啊。厉害
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-15 16:07

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表