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

2019-07-24 13:22发布

本人以前学过51单片机,知道ARM这个东西后一直向往,最近终于入手一块“战舰V3 精英板”(买板子的时候,没注意看板子资源,看到“精英”二字,以为是STM32F103ZET6板子里面最牛的,而且看价格还不是最贵的,果断买了精英板),经过几天的C语言学习、keil安装及使用学习、Jlink使用学习、工程模板(基于固件库)建立……我的STM32学习终于走上正轨。之前听过别人分享如何学习STM32,其中强调了一点,就是加入一个论坛,在论坛中跟大家一起学习,共同进步,于是今天就开贴(以前水过,从来没发过贴),从零开始学习STM32(以前学过51,但是没了解过STM32,不知道算不算从零开始),记录我的学习历程,记录一个系统性地学习STM32的过程,以求跟坛友共同进步,同时以后传递给别人准备学STM32的人一些经验。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
49条回答
忘月19920216
1楼-- · 2019-07-29 16:36
 精彩回答 2  元偷偷看……
忘月19920216
2楼-- · 2019-07-29 21:35
【2016-03-12】继续学习串口,补学中断
学习了嵌套向量中断后,对自己昨天的串口初始化程序作了代码补充和注释补充,加深了对串口配置和嵌套向量中断配置的了解;
代码修改为如下,在板子上跑了一会没有发现问题:
[mw_shl_code=applescript,true]void UART_Init(u32 baud)
{
   GPIO_InitTypeDef GPIO_InitStructure;
   USART_InitTypeDef USART_InitStructure;
   NVIC_InitTypeDef NVIC_InitStructure;

   // 初始化时钟
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA , ENABLE);   // 使能USART1、PA时钟
   
   // 初始化串口的GPIO口
   // USART1_TX -> GPIOA.9;
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //模式设置为复用推挽输出
   GPIO_Init(GPIOA, &GPIO_InitStructure);
   // USART1_RX -> GPIOA.10;
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;        //模式设置为浮空输入
   GPIO_Init(GPIOA, &GPIO_InitStructure);

   // 初始化串口1
   USART_InitStructure.USART_BaudRate = baud;   // 波特率
   USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 字长:8b
   USART_InitStructure.USART_StopBits = USART_StopBits_1;   // 停止位:1
        USART_InitStructure.USART_Parity = USART_Parity_No;   // 奇偶校验位:无
        USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  // 硬件流控制:无
        USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;   // 收、发
//   USART_DeInit(USART1);   // 复位串口1
   USART_Init(USART1, &USART_InitStructure); // 初始化串口1
   // 开启串口1接收中断
   USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);  // 开启串口1中断  
   // 开启串口1
   USART_Cmd(USART1, ENABLE);    // 使能串口1
   
   // Usart1 NVIC 配置
   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 优先级分组位长度模式2:先占优先级 2 位,从优先级 2 位
                                                   // 如果在其他地方配置过NVIC_PriorityGroup,则不用在这里配置
   // 配置串口1中断
   NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;  // 选择串口1
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;   // 抢占优先级3
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;                // 子优先级3
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // IRQ通道使能
   NVIC_Init(&NVIC_InitStructure);  // 根据指定的参数初始化VIC寄存器
     
} [/mw_shl_code]
忘月19920216
3楼-- · 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的函数或者寄存器),后面看了教程后,才知道自己没有去看外部中断的映射方式;将所有需要配置的内容配置好了之后,程序运行正常,运行结果是自己预想的;




大好大
4楼-- · 2019-07-30 05:54
加油,加油,同为初学,像楼主学习!!
whispertome
5楼-- · 2019-07-30 07:13
新人报道!!一起学习!
忘月19920216
6楼-- · 2019-07-30 11:12
 精彩回答 2  元偷偷看……

一周热门 更多>