STM32实验一:跑马灯实验

个人网站:https://chenqi.autmake.com/

接触单片机的第一个实验就是跑马灯实验,虽然实验并不难,但开始却并不容易,跑马灯实验对于老司机来说简直小菜一碟。可这对于一个不懂硬件的新手来说,真的不容易。那段时间经常看STM32中文参考手册_V10,也看了Cortex-M3权威指南。慢慢的明白了其中的原理,也知道了为什么要配置成上拉、下拉、推挽输出、复用推挽输出。

跑马灯实验大致可以分为三个步骤:

1. LED初始化

LED初始化包括时钟初始化和引脚初始化。每一个外设都有其对应的时钟,所以在使用外设之前都要先开启外设的时钟。

引脚初始化(端口初始化),本实验是要通过引脚输出高低电平来控制LED的亮灭。端口初始化主要是配置:输出引脚、输出模式、输出速率。

初始化代码如下:

/*本次跑马灯实验主要用到PB6~PB9几个端口*/
#include "LED.h"

void LED_Init(void)  //自定义Led灯初始化函数
{  
    GPIO_InitTypeDef  GPIO_InitStructure;  
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOA, ENABLE); /*使能LED灯使用的GPIO时钟*/     
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;   
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出模式  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  //以上为配置GPIO
    GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化GPIOB 
}

附上头文件:

/*头文件中主要是一些宏定义和位带操作*/
#ifndef __LED_H
#define __LED_H

#include "stm32f10x.h"

#define LED1_ON GPIO_SetBits(GPIOB, GPIO_Pin_6)
#define LED1_OFF GPIO_ResetBits(GPIOB, GPIO_Pin_6)
#define LED2_ON GPIO_SetBits(GPIOB, GPIO_Pin_7)
#define LED2_OFF GPIO_ResetBits(GPIOB, GPIO_Pin_7)
#define LED3_ON GPIO_SetBits(GPIOB, GPIO_Pin_8)
#define LED3_OFF GPIO_ResetBits(GPIOB, GPIO_Pin_8)
#define LED4_ON GPIO_SetBits(GPIOB, GPIO_Pin_9)
#define LED4_OFF GPIO_ResetBits(GPIOB, GPIO_Pin_9)
	 
//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<>第五章(87页~92页).
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C    

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08 
 
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

#define LED1  PBout(6)
#define LED2  PBout(7)
#define LED3  PBout(8)
#define LED4  PBout(9)

void LED_Init(void);

#endif

2.延时函数的编写

跑马灯实验中需要用到延时函数,这个网上有很多例子。下面给出一个比较常用且精准的延时函数。有兴趣的也可以自己去编写属于自己的延时函数。这个函数比较常用,在后面的实验中也会经常用到。

源文件:

#include "delay.h"

void delay_us(u32 nus)
{
	u32 temp;
	SysTick->LOAD = 9*nus;
	SysTick->VAL=0X00;//清空计数器
	SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
	do
	{
		temp=SysTick->CTRL;//读取当前倒计数值
	}while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
    SysTick->CTRL=0x00; //关闭计数器
    SysTick->VAL =0X00; //清空计数器
}

void delay_ms(u16 nms)
{
	u32 temp;
	SysTick->LOAD = 9000*nms;
	SysTick->VAL=0X00;//清空计数器
	SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
	do
	{
		temp=SysTick->CTRL;//读取当前倒计数值
	}while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
    SysTick->CTRL=0x00; //关闭计数器
    SysTick->VAL =0X00; //清空计数器
}

头文件:

#ifndef __DELAY_H
#define __DELAY_H

#include "stm32f10x.h"

void delay_us(u32 nus);
void delay_ms(u16 nms);

#endif

3.主函数编写

主函数就比较简单了,先调用LED的初始化函数,然后依次点亮LED。

/*引用头文件是为了调用其中定义的函数*/
#include "stm32f10x.h"
#include "delay.h"
#include "led.h"

int main(void)
{   
    LED_Init(); 
    while(1)
    {     
        LED1 = 1;
        delay_ms(200);
        LED1 = 0;
        delay_ms(200);
        LED2 = 1;
        delay_ms(200);
        LED2 = 0;
        delay_ms(200);
        LED3 = 1;
        delay_ms(200);
        LED3 = 0;
        delay_ms(200);
        LED4 = 1;
        delay_ms(200);
        LED4 = 0;
        delay_ms(200);
    }   
}

至此,跑马灯实验就结束了。新手切不可完全照搬,要根据自己的原理图来做相应的修改,加入自己的思考,才会真正成为自己的东西。

完整工程下载链接:https://pan.baidu.com/s/109sOF0eroGE0bHeTTM1Fww

你可能感兴趣的:(STM32F103RET7系列)