STM32 入门实验



实验环境准备



NANO STM32F103实验板


跑马灯程序实验

实践内容

调试技能:查看原型定义

常用函数:向GPIO的PIN管脚写入1或0

   // 向 GPIO C 的 PIN 0 写入 0
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_0,GPIO_PIN_RESET);
   // 向 GPIO C 的 PIN 0 写入 1
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_0,GPIO_PIN_SET);

背景知识:时钟结构



STM32 时钟结构


背景知识:GPIO 配置和管脚复用



STM32 GPIO结构


背景知识:硬件配置和初始化

按键输入实验

实践内容

背景知识:HAL库函数:读取 GPIO 的PIN管脚数值

背景知识:按键去抖动

UART 串口通信实验

实验操作 1

实验操作 2

// usart.c 中断完成后数据处理的代码 
unsigned int rx_cnt = 0;  // 定义全局变量 
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if(huart->Instance==USART1)//如果是串口1
  {
    USART_RX_BUF[rx_cnt]=aRxBuffer[0] ;
    rx_cnt ++;

  }
}
extern unsigned int rx_cnt ; // 声明全局变量
int main(void)
{
  HAL_Init();                     //初始化HAL库    
  Stm32_Clock_Init(RCC_PLL_MUL9); //设置时钟,72M
  delay_init(72);                 //初始化延时函数
  uart_init(115200);              //初始化串口115200
  LED_Init();                     //初始化LED 
  KEY_Init();                     //初始化按键
  int i = 0;  
  while(1) 
  {
    printf("Total RX %d Bytes: ", rx_cnt);
    for(i = 0; i < rx_cnt; i ++){
      printf("0x%X ", (uint8_t*)USART_RX_BUF[i]);
    }
    printf("\r\n");
    delay_ms(400);   
  }
}


ASCII 码表


背景知识 中断向量表和中断服务函数

; Vector Table Mapped to Address 0 at Reset
                AREA    RESET, DATA, READONLY
                EXPORT  __Vectors
                EXPORT  __Vectors_End
                EXPORT  __Vectors_Size

__Vectors       DCD     __initial_sp               ; Top of Stack
                DCD     Reset_Handler              ; Reset Handler
                DCD     NMI_Handler                ; NMI Handler
                DCD     HardFault_Handler          ; Hard Fault Handler

背景知识 UART数据传输协议



UART时序


背景知识 用 __weak 修饰符 重载STM32的库函数

__weak void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(huart);
  /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_UART_MspInit could be implemented in the user file
   */
}

背景知识 printf 输出重定向

  #if 1
  #pragma import(__use_no_semihosting)             
  //标准库需要的支持函数                 
  struct __FILE { 
    int handle; 
  }; 
  
  FILE __stdout;       
  //定义_sys_exit()以避免使用半主机模式    
  void _sys_exit(int x) { 
    x = x; 
  } 
  //重定义fputc函数 
  int fputc(int ch, FILE *f) {      
    while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
      USART1->DR = (u8) ch;      
    return ch;
  }
  #endif 

GPIO 中断 实验

实验操作1

实验操作2

while(1)
{
  printf("KEY0=%d, KEY1=%d, KEY2=%d, WK_UP=%d \r\n",KEY0, KEY1, KEY2, WK_UP);
  delay_ms(300);             //延迟打印 
}

背景知识:触发类型

背景知识:中断的优先级和中断复用

阅读理解; GPIO中断服务代码

定时器 中断 实验

实验操作1

实验操作2

  unsigned int tim_INT_cnt = 0;
  //回调函数,定时器中断服务函数调用
  void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
  {
      if(htim==(&TIM3_Handler))
      {
          tim_INT_cnt ++;
          LED1=!LED1;        //LED1反转
      }
  }
  extern unsigned int tim_INT_cnt ;
  int main(void)
  {
    HAL_Init();                     //初始化HAL库    
    Stm32_Clock_Init(RCC_PLL_MUL9); //设置时钟,72M
    delay_init(72);                 //初始化延时函数
    uart_init(9600);                        //初始化串口
    LED_Init();                     //初始化LED 
    TIM3_Init(5000-1,7200-1);       //定时器3初始化,定时器时钟为72M,分频系数为7200-1,
    //所以定时器3的频率为72M/7200=10K,自动重装载为5000-1,那么定时器周期就是500ms
    while(1)
    {
      printf("Timer INT CNT is %d \r\n", tim_INT_cnt);
    }
  }

背景知识:计数器的溢出与分频



对时钟信号计数的信号时序


背景知识:计数器对脉冲计数



对脉冲信号计数的信号时序


多位 LED 数码管 动态扫描显示实验

实验操作1

实验操作2

背景知识:动态扫描结构的数码管显示

   3比特输入 0-0-0,  8比特输出 1-1-1-1-1-1-1-0 
   3比特输入 0-0-1,  8比特输出 1-1-1-1-1-1-0-1 
   3比特输入 0-1-0,  8比特输出 1-1-1-1-1-0-1-1 
   3比特输入 0-1-1,  8比特输出 1-1-1-1-0-1-1-1 
   3比特输入 1-0-0,  8比特输出 1-1-1-0-1-1-1-1 
   3比特输入 1-0-1,  8比特输出 1-1-0-1-1-1-1-1 
   3比特输入 1-1-0,  8比特输出 1-0-1-1-1-1-1-1 
   3比特输入 1-1-1,  8比特输出 0-1-1-1-1-1-1-1 



动态扫描显示的数码管电路结构


背景知识:使用软件控制PIO管脚实现接口时序




移位寄存器接口时序


 SCK  = 0;
 SBIT = 1;
 delay(Half_Period_SCK);
 SCK  = 1;
 delay(Half_Period_SCK);
 SCK  = 0;
 SBIT = 0;



用PIO生成信号时序


综合实验 之 拆弹指令

故事背景

设计内容