yyj的STM32学习笔记



  • task1

    任务描述

    使用定时器让LED以1s为周期闪烁


    解析

    上述要求涉及gpio、定时器以及中断

    1. 配置led的过程为开启外设时钟,设置gpio为推挽输出模式
    2. 配置定时器时,本次使用了TIM6基本定时器,需要开启对应外设时钟,设置定时器ARR无缓冲,使能更新中断,设置预分频器(PSC)和自动重装载器(ARR)
    3. 配置中断需要先设置中断优先级分组,然后使用NVIC_Init函数初始化TIM6对应中断,然后配置中断服务函数,中断服务函数在开启文件中有声明和分配位置,注意在中断服务函数开头将更新中断标志位置零
    4. gpio的输出控制通过对端口输出寄存器(ODR)进行写实现
    5. 定时器的时间计数使用一全局变量实现

    总结

    1. 读数据手册很重要
    2. 细心,可以避免许多不必要的bug,节约debug的时间


  • 可以把代码也贴一下


  • 核心层

    1、是同相放大器、反相放大器。“xiang”指的是相位,不是方向。
    2、为什么要设置为推挽输出?
    3、如何计算定时器的周期?
    4、在这个过程中遇到了什么问题?又是如何解决的?



  • @liangfs

    1. 错别字,以后会在发布前看一遍,并且打算专门开一个运放专题新帖
    2. 推挽输出和开漏输出相比,能真正地输出高电平,而开漏输出需要借助上拉电阻
    3. 在配置时钟树时,定时器的周期为72MHz,在本例中,将预分频器(PSC)设置为71,对定时器进行72分频,即1MHz,将自动重装载器(ARR)设置为999,即每1000个周期产生一次中断,则最终产生中断的频率为1KHz,周期为1ms
    4. 遇到的问题大多数是工具的应用方面的,对于一个stm32项目的创建、初始化、调试、下载,刚开始时会因为遗漏某些细节而导致错误,而这种错误往往是不容易排查的
      比如,刚开始时由于没有配置时钟树导致程序不能正常运行,编译程序时由于缺少某些文件(.s之类的)而导致编译出错等等
      除此之外,还有一些不够细心导致的错误
      比如,开始焊放大器时,由于线路规划时粗心,画错了一个电阻的位置,导致出错


  • task2

    任务描述:

    1. 编写按键程序,按下时LED亮,抬起时LED灭
    2. 使用PWM波驱动舵机

    解析

    1. 按键程序最初想法是在主函数的while(1)循环中扫描GPIO的IDR寄存器,不过后来的想法是在定时器中断里每隔一段时间(如10ms)扫描一次IDR寄存器
    2. PWM波形使用通用定时器进行输出,每个通用定时器有四个通道,通过将CCRx的值与CNT的值做比较,输出高低电平,通过控制频率和占空比即可控制舵机
    3. 本次使用的舵机型号为SG90相关参数如下:
      0_1621334930659_b4aaad41-a4f1-4cbc-bbf2-f5e3e100ddd3-image.png
      0_1621334972277_c475f4a9-4978-43a0-b29c-08d0ca2fd533-image.png
    4. 本次使用STM32CubeMX进行配置和初始化,配置如下:
      0_1621335064573_c870d81f-3c3e-4ca4-8a9b-acdc95d0f030-image.png


  • task3


    任务描述:

    完成单个按键状态检测,能够利用指示灯识别单击、双击、长按


    解析

    1. 按键按下状态的检测不能直接使用中断,由于机械按键会在按下、抬起时产生抖动,会触发多次中断,故需要进行消抖处理,抖动一般在10ms以内,本次使用延时消抖,即在检测到按下或抬起后在一段时间后再次检测,确认其确实发生了按下或者抬起
    2. 按键检测以时间片的原则进行,使用TIM6计时器每隔10ms检测一次按键状态,使用两个变量分别储存按下、抬起的时间
    3. 使用一个变量记录所处的状态,当检测到按键状态发生变化时,根据现在所处的状态和变量的值进行动作
    4. 本次设定为2s以下为单击,2s以上为长按,第一次单击后1s内再次单击为双击

    代码


    由于代码由cube生成,比较繁琐,故只贴自己写的部分


    #define MAX 999
    
    #define TIME_CLICK_PRESS 200  //点击和长按分界线
    #define TIME_WAIT 100       
    
    #define FLAG_PLAIN 0          //普通状态
    #define FLAG_FIRST_HIT 1      //第一次被按下
    #define FLAG_WAIT_SECOND_HIT 2//等待第二次被按下
    #define FLAG_SECOND_HIT 3     //第二次被按下
    
    #define KEY_TIME_INCREASE(x) (((x) >= MAX) ? MAX : ((x) + 1))       //代替自增操作,防止溢出,对变量的值做限制
    

    变量

    uint32_t POSITIVE = 0, NEGATIVE = 2;      //按下、抬起时间
    uint16_t FLAG = FLAG_PLAIN;               //状态
    

    主要函数

    uint16_t if_KeyHit(void)            //检测按键状态
    {
        if(GPIOA->IDR & 0x1)
        {
            return 0;
        }
        else
        {
            return 1;
        }
    }
    
    void TimeSlicer(void)               //管理时间变量和状态转换
    {
        if (if_KeyHit()) //检测到按键按下
        {
            if (POSITIVE > 1) //正常继续按下状态
            {
                POSITIVE = KEY_TIME_INCREASE(POSITIVE);
                StateSwitch();
                NEGATIVE = 0;
            }
            else if (POSITIVE == 1) //确认切换为按下
            {
                POSITIVE = 2;
                StateSwitch();
                NEGATIVE = 0;
            } 
            else //处于抬起状态,需确认是否按下
            {
                NEGATIVE = KEY_TIME_INCREASE(NEGATIVE);
                POSITIVE = 1;
            }
        }
        else //检测到按键抬起
        {
            if (NEGATIVE > 1) //正常继续抬起状态
            {
                NEGATIVE = KEY_TIME_INCREASE(NEGATIVE);
                StateSwitch();
                POSITIVE = 0;
            }
            else if (NEGATIVE == 1) //确认抬起状态
            {
                NEGATIVE = 2;
                StateSwitch();
                POSITIVE = 0;
            }
            else //处于按下状态,需确认是否抬起
            {
                POSITIVE = KEY_TIME_INCREASE(POSITIVE);
                NEGATIVE = 1;
            }
        }
    }
    
    void StateSwitch(void)                  //状态操作和转换
    {
        switch (FLAG)
        {
        case FLAG_PLAIN:
            if(if_KeyHit())                         //按键按下
            {
                FLAG = FLAG_FIRST_HIT;
            }
            break;
        case FLAG_FIRST_HIT:
            if(!if_KeyHit())                        //按键松开
            {
                if (POSITIVE > TIME_CLICK_PRESS)    //长按
                {
                    FLAG = FLAG_PLAIN;
                }
                else                                //第一次为点击
                {
                    FLAG = FLAG_WAIT_SECOND_HIT;
                    State_0();
                }     
            }
            else
            {
                if(POSITIVE > TIME_CLICK_PRESS)
                {
                    State_3();
                }
            }
            
            break;
        case FLAG_WAIT_SECOND_HIT:
            if(!if_KeyHit())                         //按键没有按下
            {
                if (NEGATIVE > TIME_WAIT)           //等待时间已过,为单击
                {
                    State_1();
                    FLAG = FLAG_PLAIN;
                }    
            }
            else                                    //按键按下
            {
                FLAG = FLAG_SECOND_HIT;
            }
            break;
        case FLAG_SECOND_HIT:
            if(!if_KeyHit())                        //按键抬起
            {
                if(POSITIVE < TIME_CLICK_PRESS)     //第二次为点击
                {
                    State_2();
                    FLAG = FLAG_PLAIN;
                }
                else                                //第二次为长按
                {
                    State_1();
                    State_3();
                    FLAG = FLAG_PLAIN;
                }   
            }
            break;
        default:;
        } 
    }
    
    void State_0(void)                      //用LED灯指示检测到的按键操作类型
    {
        GPIOF->ODR |= (0x1 << 8);
        GPIOF->ODR |= (0x1 << 9);
    }
    
    void State_1(void)
    {
        GPIOF->ODR &= ~(0x1 << 8);
        GPIOF->ODR |= 0x1 << 9;
    }
    
    void State_2(void)
    {
        GPIOF->ODR |= 0x1 << 8;
        GPIOF->ODR &= ~(0x1 << 9);
    }
    
    void State_3(void)
    {
        GPIOF->ODR &= ~(0x1 << 8);
        GPIOF->ODR &= ~(0x1 << 9);
    }
    

    总结

    这次开始用的板子有点问题,导致找了两天bug也没找出来,最后换了块板子,效果还不错,硬件的问题太折磨人了555


 

Copyright © 2018 bbs.dian.org.cn All rights reserved.

Looks like your connection to Dian was lost, please wait while we try to reconnect.