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

2019-07-24 13:22发布

本人以前学过51单片机,知道ARM这个东西后一直向往,最近终于入手一块“战舰V3 精英板”(买板子的时候,没注意看板子资源,看到“精英”二字,以为是STM32F103ZET6板子里面最牛的,而且看价格还不是最贵的,果断买了精英板),经过几天的C语言学习、keil安装及使用学习、Jlink使用学习、工程模板(基于固件库)建立……我的STM32学习终于走上正轨。之前听过别人分享如何学习STM32,其中强调了一点,就是加入一个论坛,在论坛中跟大家一起学习,共同进步,于是今天就开贴(以前水过,从来没发过贴),从零开始学习STM32(以前学过51,但是没了解过STM32,不知道算不算从零开始),记录我的学习历程,记录一个系统性地学习STM32的过程,以求跟坛友共同进步,同时以后传递给别人准备学STM32的人一些经验。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
49条回答
忘月19920216
2019-07-30 00:42
在中断这里吃了很多苦头,还是因为自己资料没看全,开始想不看教程和例程,直接看固件库使用手册和STM32参考手册就完成程序,结果整了几个小时中断都还没有正常工作,仅仅因为参考手册的外部中断/事件线路映像我没有去看,这个一定要记着,使用外设的时候要记得看它的映射关系;
【2016-03-13】原子SYSTEM->usart.c使用和外部中断使用
外部中断配置过程:
①初始化想要映射的IO口为输入;
②开启AFIO功能复用IO时钟;
③将外部中断映射到具体的IO口;
④根据对应中断初始化EXTI寄存器;
⑤根据对应中断初始化NVIC寄存器;
⑥编写对应的中断服务函数;
本次学习中遇到过的问题:
①没有开启AFIO功能复用IO时钟;
②没有了解外部中断/事件线路映像;


1、查看板子电路图,物 {MOD}作为外部中断的IO口;
2、查看库函数指南、参考手册对应的内容,查看原子的例程并理解过程;
3、复制自己的串口工程(里面使用了SYSTEM文件夹里的usart.c,还包含以前自己写的LED,BEEP,KEY),写代码;
4、仿真调试,思考总结,记录发帖;


1、查看板子电路图,物 {MOD}作为外部中断的IO口;
    就选择按键KEY0和KEY1所连接的IO口作为外部中断源;
2、查看库函数指南、参考手册对应的内容,查看原子的例程并理解过程;
外部中断配置过程:
    ①初始化想要映射的IO口为输入;
    ②开启AFIO功能复用IO时钟;
    ③将外部中断映射到具体的IO口;
    ④根据对应中断初始化EXTI寄存器;
    ⑤根据对应中断初始化NVIC寄存器;
    ⑥编写对应的中断服务函数;   
3、复制自己的串口工程(里面使用了SYSTEM文件夹里的usart.c,还包含以前自己写的LED,BEEP,KEY),写代码;
    串口直接使用SYSTEM文件夹里的usart.c;
    然后按照外部中断配置步骤编写exti.c:
[mw_shl_code=applescript,true]#include "exti.h"
#include "stm32f10x_exti.h"
#include "key.h"
#include "usart.h"
#include "led.h"
#include "delay.h"

u8 state = 0;

void BOARD_EXTI_Init(void)
{  
   EXTI_InitTypeDef EXTI_InitStructure;
   NVIC_InitTypeDef NVIC_InitStructure;
   
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);        //使能复用功能时钟

   // 初始化外部中断EXTI寄存器
   // KEY0 -> PE4 -> EXTI4;
   GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource4);  // 外部中断4映射到PE4
   EXTI_InitStructure.EXTI_Line = EXTI_Line4;  // 外部中断4
   EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;   // 设置为中断请求
   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;   // 设置为下降沿触发
   EXTI_InitStructure.EXTI_LineCmd = ENABLE;    // 开启中断
   EXTI_Init(&EXTI_InitStructure);
   // KEY1 -> PE3 -> EXTI3;
   GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);  // 外部中断3映射到PE3
          EXTI_InitStructure.EXTI_Line=EXTI_Line3;
          EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;       
          EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
          EXTI_Init(&EXTI_InitStructure);                  //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
   
   // 配置外部中断NVIC寄存器
   NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;  // 外部中断3
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;   // 抢占优先级2
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;                // 子优先级2
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // IRQ通道使能
   NVIC_Init(&NVIC_InitStructure);  // 根据指定的参数初始化VIC寄存器
   NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;  // 外部中断4
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;   // 抢占优先级2
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;                // 子优先级2
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // IRQ通道使能
   NVIC_Init(&NVIC_InitStructure);  // 根据指定的参数初始化VIC寄存器

}

// 外部中断3中断服务函数
// KEY1 -> PE3 -> EXTI3;
void EXTI3_IRQHandler(void)
{
   delay_ms(5);
   
   if(KEY1 == 0)
   {
      EXTI->IMR = 0x0;// 屏蔽外部中断
      state = EXTI3_TRIGGER;
   }
   else
      ;
   EXTI_ClearITPendingBit(EXTI_Line3);  //清除LINE3上的中断标志
}

// 外部中断4中断服务函数
// KEY0 -> PE4 -> EXTI4;
void EXTI4_IRQHandler(void)
{
   delay_ms(5);
   
   if(KEY0 == 0)
   {
      EXTI->IMR = 0x0;  // 屏蔽外部中断
      state = EXTI4_TRIGGER;
   }
   else
      ;
   
   EXTI_ClearITPendingBit(EXTI_Line4);  //清除LINE4上的中断标志
}
[/mw_shl_code]
    然后为其写一个exti.h:
[mw_shl_code=applescript,true]#ifndef __EXTI_H
#define __EXTI_H         
#include "sys.h"

#define  NO_TRIGGER    0
#define  EXTI3_TRIGGER 1
#define  EXTI4_TRIGGER 2
extern u8 state;

void BOARD_EXTI_Init(void);
                                                     
#endif
[/mw_shl_code]
    IO口初始化就在key.c的KEY_Init函数里初始化了;
    最后main.c这样写:
[mw_shl_code=applescript,true]#include "stm32f10x.h"
#include "led.h"
#include "beep.h"
#include "usart.h"
#include "delay.h"
#include "exti.h"
#include "key.h"

int main(void)
{       
   u8 already_printf = 0;
   
   LED_Init();  
   BEEP_Init();
   KEY_Init();
   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
   uart_init(115200);
   delay_init();
   BOARD_EXTI_Init();
   
   // 初始化成功提示
   LED1 = 0;
   BEEP = 1;
   delay_ms(100);
//   LED0 = 0;
   LED1 = 1;
   BEEP = 0;
   printf(" 请按键触发中断 ");
   
   while(1)
        {
      switch(state)
      {
         case NO_TRIGGER:
                  EXTI->IMR |= (1<<3)|(1<<4);
                  LED0 = 0;
                  LED1 = 0;
                  already_printf = 0;
                  break;
         case EXTI3_TRIGGER:
                  LED0 = 0;
                  LED1 = 1;
                  if(already_printf ==0)
                  {
                     already_printf = 1;
                     printf(" 触发外部中断3,已锁定为EXTI3_TRIGGER状态,请发送任意字符加回车返回初始状态 ");
                     break;
                  }
                  else if(USART_RX_STA&0x8000)
                  {
                     printf(" 发送成功,返回初始状态... ");
                     printf(" 已返回初始状态,请按键触发中断 ");
                     state = NO_TRIGGER;
                     USART_RX_STA &= 0x0;
                     break;
                  }
                  else
                  {
                     break;
                  }
         case EXTI4_TRIGGER:
                  LED0 = 1;
                  LED1 = 0;
                  if(already_printf ==0)
                  {
                     already_printf = 1;
                     printf(" 触发外部中断4,已锁定为EXTI4_TRIGGER状态,请发送任意字符加回车返回初始状态 ");
                     break;
                  }
                  else if(USART_RX_STA&0x8000)
                  {
                     printf(" 发送成功,返回初始状态... ");
                     printf(" 已返回初始状态,请按键触发中断 ");
                     state = NO_TRIGGER;
                     USART_RX_STA &= 0x0;
                     break;
                  }
                  else
                  {
                     break;
                  }
         default:
                  LED0 = 1;
                  LED1 = 1;
                  printf(" 进入未知状态,1秒后强制跳转到初始状态... ");
                  delay_ms(1000);
                  printf(" 已返回初始状态,请按键触发中断 ");
                  state = NO_TRIGGER;
                  break;
      }
   }
}
[/mw_shl_code]
4、仿真调试,思考总结,记录发帖;

    调试的结果,预想的是,在初始状态可以按键触发外部中断,进入中断后屏蔽所有外部中断,不能再触发,然后串口向板子发送一个回车后再次进入初始状态,可以继续按键触发对应中断;
    这次由于资料没看全,导致时钟和中断映射没有配好(开始是以为IO口能作为任意一号外部中断,想把PE4、PE3分别作为外部中断0和1,可是怎么也找不到映射到0和1的函数或者寄存器),后面看了教程后,才知道自己没有去看外部中断的映射方式;将所有需要配置的内容配置好了之后,程序运行正常,运行结果是自己预想的;




一周热门 更多>