2. 通用并行接口GPIO
2.1 GPIO结构及寄存器说明
2.2 GPIO设计实例
2.2.1 直接操作寄存器软件设计
2.2.2 使用库函数范例程序(v2.0.1)
2.2.3 用GPIO控制LCD
2.1 GPIO结构及寄存器说明
- GPIO包括多个16位I/O端口,每个端口可以独立设置3种输入方式和4种输出方式,并可独立地置位或复位
- GPIO由寄存器、输入驱动器和输出驱动器等部分组成
- GPIO通过7个32位寄存器进行操作
偏移地址 |
名称 |
类型 |
复位值 |
说明 |
0X00 |
CRL |
读/写 |
0X44444444 |
配置寄存器低位(每个端口4位) |
0X04 |
CRH |
读/写 |
0X44444444 |
配置寄存器高位(每个端口4位) |
0X08 |
IDR |
读 | 0X0000 |
16位输入数据寄存器 |
0X0C |
ODR |
读/写 |
0X0000 |
16位输出数据寄存器 |
0X10 |
BSRR |
写 | 0X00000000 |
位置位/复位寄存器 |
0X14 |
BRR |
写 | 0X0000 |
位复位寄存器 |
0X18 |
LCKR |
读/写 | 0X00000 |
配置锁定寄存器 |
- 每个端口的4个配置位是CNF[1:0]和MODE[1:0]
CNF[1:0] | MODE[1:0] | 输入配置 | CNF[1:0] | MODE[1:0](2) | 输出配置 |
00 | 00 | 模拟输入 | 00 | 01/10/11 | 通用推挽输出 |
01 | 00 | 浮空输入(复位状态) | 01 | 01/10/11 | 通用开漏输出 |
10 | 00 | 上拉/下拉输入(1) | 10 | 01/10/11 | 复用推挽输出 |
11 | 00 | 保留 | 11 | 01/10/11 | 复用开漏输出 |
注:(1)ODR = 1:上拉,ODR = 0;下拉
(2)01/10/11 依次对应最大输出频率为10MHz/2MHz/50MHz
2.2 GPIO设计实例
- 系统包括Cortex-M3 CPU(内嵌SYSTick定时器)、存储器、2个按键接口和4个LED接口,实现用2个按键控制4个LED的流水显示方向,4个LED流水显示,每1s移位1次
2.2.1 直接操作寄存器软件设计
- 头文件(main.h)
//包含结构定义头文件
#include "stm32f10x_map.h"
//声明函数
void SysTick_Init(void);
void SysTick_Proc(void);
void Key_init(void);
void Key_Proc(void);
void Led_Init(void);
void Led_Proc(void);
- 源文件(main.c)(主程序)
//包含头文件
#include "main.h"
//定义全局变量
char Clag = 0 , sec = 0 , secl = 0 ;
unsigned short led_dat[4] = {1 << 12 , 1 << 13 , 1 << 14 , 1 << 15 };
char led_num = 0 ;
//主函数
int main(void)
{
SysTick_Init(); //系统定时器初始化
Key_Init(); //按键接口初始化
Led_Init(); //LED接口初始化
while(1)
{
SysTick_Proc(); //定时器处理函数
Key_Proc(); //按键处理函数
Led_Proc(); //LED处理函数
}
}
- 源文件(main.c)定时器子程序
//系统定时器初始化子程序
void SysTick_Init(void)
{
SysTick->LOAD = 1E6; //设置(时钟频率)
SysTick->CTRL = 1 ; //启动定时器
}
//定时处理子程序
void SysTick_Proc(void)
{
if(SysTick->CTRL & 1<<16) //1s时间到
{
sec += 1 ;
if((sec & 0xf) > 9)
sec += 6; //2-10进制调整
}
}
- 源文件(main.c)(按键子程序)
//按键接口初始化子程序
void Key_Init(void)
{
RCC->APB2ENR |= 1<<3 ; //开启按键接口(GPIOB)时钟
}
//按键处理子程序
void Key_Proc(void)
{
if(~GPIOB->IDR & 1<<8) //KEY1按下(PB.08=0)
flag = 0;
if(~GPIOB->IDR & 1<<9)
flag = 1; //KEY2按下(PB.09=0)
}
- 源文件(main.c)(LED子程序)
//LED接口初始化程序
void Led_Init(void)
{
RCC->APB2ENR |= 1<<3; //开启LED接口(GPIOB)时钟
GPIOB->CRH &= 0x0000ffff;
GPIOB->CRH |= 0x33330000; //PB.15-PB.12通用推挽输出
}
//LED处理子程序
void Led_Proc(void)
{
if(sec != sec1 ) //1s时间到
{
sec1 = sec;
GPIOB->BSRR = 0xf000; //灭所有LED
GPIOB->BRR = led_dat[led_num]; //亮指定LED
if(flag)
{
if(++led_num == 4)
led_num = 0; //左环移
}
else
{
if(led_num-- == 0)
led_num = 3; //右环移
}
}
}
使用仿真器调试和运行目标程序文件
- 使用仿真器调试和运行目标程序文件通过仿真硬件实现,不需要目标硬件
- 使用仿真器调试和运行目标程序还具有分析(Analysis)功能,包括逻辑分析仪(Logic Analyzer)、性能分析仪(Performance Analyzer)和代码覆盖率(Code Coverage)
- 逻辑分析仪(Logic Analyzer)是非常有用的调试功能
2.2.2 使用库函数范例程序
- 在C:\Keil\ARM\Examples\ST\STM32F10xFWLib\Examples\SysTick目录包含有使用库函数的SysTick和GPIO范例程序
- 其中包含下列7个文件:
main.c:主程序文件
main.h:主程序头文件
stm32f10x_it.c:中断服务程序文件
stm32f10x_it.h:中断服务程序头文件
platform_config.h:开发版配置文件
stm32f10x_conf.h:库配置文件
readme.txt:范例说明文件
2.2.3 用GPIO控制LCD
1、LCM046简介
- LCM046是4位多功能通用型8段(8.8.8.8)液晶显示模块内置显示RAM,可以显示任意字段笔画,3-4线串行接口
引脚 功能 方向 说明 引脚 功能 方向 说明
1 /CS 输入 片选(内部上拉) 6 VLCD 输入 对比度调整
2 /RD 输入 读(内部上拉) 7 VDD 输入 电源(2.7-5.5V)
3 /WR 输入 写(内部上拉) 8 IRQ 输出 定时器中断
4 DA 双向 数据(内部上拉) 9 BZ 输出 蜂鸣器正极
5 GND - 地 10 /BZ 输出 蜂鸣器负极
- LCM046写操作时序
- 写命令格式为:100命令代码(C7-C0:8位)0,共12位
- 写数据格式为:101地址(A5-A0:6位)数据(D0-D3:4位),共13位
- LCM046常用命令代码
命令代码 功能 命令代码 功能
0000 0000 关振荡器 0001 0100 定义外部晶体振荡器工作
0000 0001 开振荡器 0001 1000 定义内部RC振荡器工作
0000 0010 关显示器 0010 1001 初始化模块
0000 0011 开显示器
- 初始化模块的步骤是:
(1)初始化模块命令 (2)定义内部RC振荡器工作
(3)开振荡器 (4)开显示器
- LCM046地址数据
地址 数据 地址 数据
A5-A0 D3 D2 D1 D0 A5-A0 D3 D2 D1 D0
000000 COL 1E 1F 1A 000001 1D 1C 1G 1B
000010 DP1 2E 2F 2A 000011 2D 2C 2G 2B
000100 DP2 3E 3F 3A 000101 3D 3C 3G 3B
000110 DP3 4E 4F 4A 000111 4D 4C 4G 4B
2、GPIO控制LCM046程序设计(写子程序)
//LCM046写子程序
//入口参数:data=写数据,bit=数据位
void Lcd_Write(short data, char bit)
{
short m,n;
GPIOA->BRR = 1<<4; // PA.04(LCD_CS)=0
for(m=bit-1; m>=0; m--)
{
GPIOA->BRR = 1<<5; // PA.05(LCD_WR)=0
if(data & 1<<m)
GPIOA->BSRR = 1<<7; // PA.07(LCD_DA)=1
else
GPIOA->BRR = 1<<7; // PA.07(LCD_DA)=0
GPIOA->BSRR = 1<<5; // PA.05(LCD_WR)=1
for(n=0; n<5; n++); // 延时
}
GPIOA->BSRR = 1<<7; // PA.07(LCD_DA)=1
GPIOA->BSRR = 1<<4; // PA.04(LCD_CS)=1
}
2、GPIO控制LCM046程序设计(写命令/数据子程序)
//LCM046写命令子程序
//入口参数:code-8位命令代码
void Lcd_Code_Write(char code)
{
short data = (4<<9)+(code <<1);
Lce_Write(data,12);
}
//LCM046写数据子程序
//入口参数:addr-6位地址,data-4位数据
void Lcd_Data_Write(char addr, char data)
{
short data1 = (5<<10)+(addr<<4)+data;
Lcd_Write(data1,13);
}
2、GPIO控制LCM046程序设计(初始化子程序)
//LCM046初始化子程序
void Lcd_Init(void)
{
RCC->APB2ENR |= 1<<2; //开启LCD接口(GPIOA)时钟
GPIOA->CRL |= 0x70770000; //PA.07、PA.05和PA.04通用开漏输出
GPIOA->ODR |= 0x00b0; //PA.07、PA.05和PA.04输出高电平
Lcd_Code_Write(0x29); //初始化模块
Lcd_Code_Write(0x18); //内部振荡器
Lcd_Code_Write(0x01); //开振荡器
Lcd_Code_Write(0x03); //开显示器
}
2、GPIO控制LCM046程序设计(显示处理子程序)
//LCM046显示处理子程序
//入口参数:data1-前2位显示数据,data2-后2位显示数据,dot-COL DP1 DP2 DP3
void Lcd_Proc(char data1,char data2,char dot)
{
char i;
//0-9,A-F倒显编码(格式AFE.BGCD)
char lcd_code[16]={0xeb,0x60,0xad,0xe5,0x66,0xe7,0xcf,0x61,//0 1 2 3 4 5 6 7
0xef,0xef,0x6f,0xce,0x8b,0xec,0x8f,0x0f//8 9 A B C D E F
};
short data = (data1<<8)+data2;
for( i=0; i<4 ;i++)
{
data1 = lcd_code[(data>>(4*i))&0xf];
Lcd_Data_Write(2*i,(data1>>4)+((dot>>(3-i))&0x1));
Lcd_Data_Write(2*i+1,data1&0xf);
}
}
2、GPIO控制LCM046程序设计(信号波形)