个人网站: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