目录
一、硬件电路设计
二、软件设计
1、工程配置
?2、程序编写
(1)led头文件
(2)Led_Init()函数编写
三、实验测试
?四、使用宏定义
1、修改后的led.h中程序
2、修改后的Led_Init()初始化函数
3、main函数中点亮LED灯
五、使用位带方式
1、创建system文件
2、修改程序代码
六、工程下载连接
一、硬件电路设计
?电气原理图
8个LED灯采用共阳极方式接在PC口的PC0-PC7引脚上,输出低电平为点亮、高电平熄灭。
测试实物开发板
二、软件设计
复制第一节所创建的库函数模板空工程,重新编译没有错误没有警告。然后开始接下来的工程配置和代码编写等工作。
1、工程配置
在工程文件中新建文件夹取名APP,用来存放外部设备驱动程序。在APP文件夹中新建文件夹led,用以存放led灯相关的驱动程序。
(1)led文件夹路径添加
若不添加后面程序编译将报错。
(2)创建led驱动程序文件
分别创建led.c和led.h文件,保存在APP-led文件夹中
(3)工程Project中新建APP分组
?(4)工程APP中添加led.c文件
?2、程序编写
(1)led头文件
#ifndef _LED_H_
#define _LED_H_
#include "stm32f10x.h"
void Led_Init(void); //led Init Function
#endif
#ifndef _LED_H_
#define _LED_H
_ #endif
的作用是:
如果led.h第一次被引用,那么__LED_H没有被定义,所以#define __LED_H和#endif 中间的头文件内容就被执行,也就是头文件内容被定义。那么如果led.h第二次被引用,由于__LED_H已经被第一次引用时定义了,所以不会执行#define __LED_H和#endif 中间的头文件内容,也就是不会重复定义头文件内容。
这样,可以避免头文件的内容被重复定义。头文件中定义的变量不存在重复声明或定义
(2)Led_Init()函数编写
①GPIO_InitTypeDef结构体变量定义和赋值
在STM32的GPIO的驱动文件上? 找到GPIO_StructInit()。
?在Led_Init()中定义GPIO_InitTypeDef结构体变量,同时给结构体变量成员GPIO_Pin、GPIO_Speed、GPIO_Mode赋值
GPIO_Pin:需要使用的IO引脚
GPIO_Speed:IO输出最高带宽频率
GPIO_Mode:IO输出模式,四种模式。一般常用为普通推挽输
普通推挽输出(GPIO_Mode_Out_PP:电平匹配场合。低电平0V、高电平3.3V
普通开漏输出(GPIO_Mode_Out_OD):电平不匹配场合,一般5V以上
复用推挽输出(GPIO_Mode_AF_PP):用作串口的输出
复用开漏输出(GPIO_Mode_AF_OD):用在IIC
?具体要赋什么值,鼠标分别放在GPIO_Pin_All、GPIO_Speed_2MHz、GPIO_Mode_IN_FLOATING上面右击,然后选择Go To Definition of 'XXX'跳转到其头文件中相应的宏、枚举定义,如下图所示
?GPIO_Pin
GPIO_Speed
GPIO_Mode
结构体变量重新赋值后的程序如下
②时钟使能
在STM32的rcc.c文件夹中找到RCC_APB2PeriphClockCmd(),使能或者失能 APB2 外设时钟
第二个参数就是ENABLE或者DISENABLE,
参数1选择如下:
另外说明:
(1)APB2负责AD,I/O,串口1,高级定时器TIM。如上图参数1表格所示。
(2)APB1负责DA,串口2,3,4,5,普通定时器TIM, USB , IIC ?, CAN。如下图所示
?最终的LED代码如下
void Led_Init()
{
GPIO_InitTypeDef GPIO_InitTypeStruct; //结构体定义
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); //时钟使能
GPIO_InitTypeStruct.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitTypeStruct.GPIO_Speed=GPIO_Speed_50MHz; //输出口的最高带宽频率:50MHz
GPIO_InitTypeStruct.GPIO_Mode=GPIO_Mode_AF_PP; //普通推挽输出
GPIO_Init(GPIOC,&GPIO_InitTypeStruct); //初始化GPIO的C口
//设置IO高电平输出,LED在初始状态下都保持熄灭状态
GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
}
(3)在Main.c主函数中点亮led灯
首先引用led.h头文件,调用Led_Init()。
Main程序
#include "stm32f10x.h"
#include "led.h"
int main()
{
Led_Init();
while(1)
{
//8个引脚都设置为低电平,将8个LED灯都点亮
GPIO_ResetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
}
}
三、实验测试
编译没有错误,生成HEX文件。
使用烧录软件,将HEX文件写到单片机中
?实验结果实物展示
?四、使用宏定义
为了方便代码移植,将引脚、IO口和时钟等在头文件中使用宏定义,代码在移植到别的工程项目中,只需要修改宏定义文件即可。宏定义如下。
#define LED_PORT_RCC RCC_APB2Periph_GPIOC
#define LED_PIN GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7
#define LED_PORT GPIOC
然后将程序中的原变量名,修改为定义的宏名称即可
1、修改后的led.h中程序
#ifndef _LED_H_
#define _LED_H_
#include "stm32f10x.h"
#define LED_PORT_RCC RCC_APB2Periph_GPIOC
#define LED_PIN (GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7)
#define LED_PORT GPIOC
void Led_Init(void); //led Init Function
#endif
2、修改后的Led_Init()初始化函数
void Led_Init()
{
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量
RCC_APB2PeriphClockCmd(LED_PORT_RCC,ENABLE);
GPIO_InitStructure.GPIO_Pin=LED_PIN; //选择要设置的IO口
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //设置推挽输出模式
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //设置传输速率
GPIO_Init(LED_PORT,&GPIO_InitStructure); /* 初始化GPIO */
GPIO_SetBits(LED_PORT,LED_PIN); //设置IO口高电平输出,熄灭所有LED灯
}
3、main函数中点亮LED灯
#include "stm32f10x.h"
#include "led.h"
int main()
{
Led_Init();
while(1)
{
//
GPIO_ResetBits(LED_PORT,GPIO_Pin_0); //点亮LED1
GPIO_ResetBits(LED_PORT,GPIO_Pin_1); //点亮LED2
GPIO_ResetBits(LED_PORT,GPIO_Pin_2); //点亮LED3
//GPIO_ResetBits(GPIOC,GPIO_Pin_0); //点亮LED1
}
}
五、使用位带方式
1、创建system文件
创建system.c源文件和system.h头文件,创建Public文件夹和Public文件组。使用前面讲解的方法添加文件
将stm32f10x.h文件在system.h头文件中引用,其它文件中不在引用,只需要引用system.h即可。
2、修改程序代码
system.c中只调用system.h,没有其它代码操作。
system.h中代码如下
#ifndef _system_H
#define _system_H
#include "stm32f10x.h"
//位带操作,实现类似于51单片机中IO口操作方式
//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?úμ??·ó3é?
#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) //输入
#endif
修改后的led.h代码如下
#ifndef _LED_H_
#define _LED_H_
#include "system.h"
#define LED_PORT_RCC RCC_APB2Periph_GPIOC
#define LED_PIN (GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7)
#define LED_PORT GPIOC
#define led1 PCout(0) //D1灯连接引脚PC0
#define led2 PCout(1) //D2灯连接引脚PC1
#define led3 PCout(2) //D3灯连接引脚PC2
void Led_Init(void); //led Init Function
#endif
修改后的main代码如下
#include "system.h"
#include "led.h"
int main()
{
Led_Init();
while(1)
{
//
// GPIO_ResetBits(LED_PORT,GPIO_Pin_0); //点亮LED1
// GPIO_ResetBits(LED_PORT,GPIO_Pin_1); //点亮LED2
// GPIO_ResetBits(LED_PORT,GPIO_Pin_2); //点亮LED3
// //GPIO_ResetBits(GPIOC,GPIO_Pin_0); //点亮LED4
led1=0;
led2=0;
}
}
通过这种定义方式,这样就可以像在C51单片机中那样操作IO口了。
若要取反,led1=~led1;
六、工程下载连接
https://download.csdn.net/download/panjinliang066333/86507279
|