GPIO及其应用举例.docx
《GPIO及其应用举例.docx》由会员分享,可在线阅读,更多相关《GPIO及其应用举例.docx(17页珍藏版)》请在冰豆网上搜索。
GPIO及其应用举例
计算机基本知识第四章GPIO多路复用器及其应用举例
4.1F2812端口概述
DSPF2812提供了56个多功能引脚,这些引脚像单片机的P3端口一样,具有第二功能。
一方面,这些引脚作为片内某些资源的输入或输出引脚,实现片内某些外设功能。
另一方面,在片内外设功能不被使能情况下,该端口又可以作为一般的输入输出端口使用,实现普通I/O口输入或输出高低电平信号的功能。
以GPIOF0_GPIOF4为例,当片内SPI外设被使能时,上述引脚作为SPI接口的数据通讯引脚使用,GPIOF2作为SPICLKA,为SPI通讯的时钟脉冲信号,用来输出或输入时钟信号,GPIOF0作为SPIMOSIA,用来作为SPI口的从机输入主机输出端口。
在SPI外设功能不被使能时,该四个端口作为普通的输入输出I/O口使用。
F2812的GPIO多路复用器在将有关引脚用作数字I/O时,将端口分为五组,组成两个16位的数字I/O口GPIOA和GPIOB;组成一个15位的数字I/O口GPIOF。
4位的数字I/O口GPIOD;一个3位的数字I/O口GPIOE。
如下图所示。
图4.1GPIO多路复用端口
4.2GPIO控制寄存器
F2812的多功能端口作为GPIO端口使用时,可以通过使用GPIO的有关寄存器可以选择和控制这些共享引脚的操作,。
例如:
通过GPxMUX寄存器可以把这些引脚作为数字I/O或片内外设I/O口。
如果选择某个引脚作为数字I/O口,则可以通过GPxDIR寄存器来设置引脚的方向;另外,可以通过GPxQUAL寄存器来改善输入信号,有效的消除输入信号的毛刺脉冲的干扰。
每个GPIO通过功能控制、方向、数据、设置、清除和反转触发寄存器来控制。
GPxMUX寄存器——
每个I/O口都有一个功能选择寄存器,用来配置I/O工作在外设操作模式或数字量I/O模式。
例如:
存储器映像寄存器GPAMUX(0x70C0,容量16位),作为GPIOA组端口的功能选择寄存器。
GPBMUX(0x70C4,容量16位)为GPIOB口功能选择寄存器。
复位期间所有GPIO配置成I/O功能。
GPxMUX.bit=0,配置成I/O功能;
GPxMUX.bit=1,配置成外设功能;
GPxDIR寄存器——
每个I/O口都有方向控制寄存器,用来配置I/O的方向。
复位时,所有GPIO位输入。
GPxDIR.bit=0,引脚配置为数字量输入;
GPxDIR.bit=1,引脚配置为数字量输出;
GPxDAT寄存器——
每个I/O口都有数据寄存器,如果I/O配置为输入,反映当前经过量化后I/O口的输入信号的状态。
复位时,所有GPIO位输入。
GPxDAT.bit=0,且引脚配置输出功能,将相应的引脚拉低;
GPxDAT.bit=1,且引脚配置输出功能,将相应的引脚拉高;
GPxQUAL寄存器
从GPxDAT寄存器读取的相应引脚状态,通过量化寄存器GPxQUAL量化输入信号,消除外部噪声。
GPxQUAL寄存器用来量化采样周期;
采样窗口是6个采样周期宽度,只有当所有采样的数据相同时,输出才会改变。
这个功能可以有效地消除输入信号的毛刺脉冲的干扰。
图4.2GPxQUAL寄存器量化采样
4.3GPIO应用举例——8×8LED点阵控制
应用DSP的GPIO端口控制输出数据,控制8×8点阵进行图形或字符显示。
4.3.1硬件电路设计
电路如下图所示。
74164为串行输入并行输出移位寄存器。
设计中,选择两片74164分别控制点阵模块的行和列,控制数据从DSP端口输出。
其中,GPIOF0输出数据与U1的74164的A端口相连,GPIOF1与B口连接,两个端口用来输出对点阵进行显示控制的数据,GPIOF2输出模拟时钟脉冲信号,与74164的CLK引脚相连,GPIOF3连接CLR清零端。
DSPF2812的GPIOB0---GPIOB3与另外一片74164的A、B、CLR、CLK对应相连。
如图所示。
图4.38×8点阵电路图
4.3.1.18×8点阵内部电路
点阵内部为排列的8×8个发光二极管,每一个二极管都在行线和列线的交点处,要同时受到行和列的控制才能点亮。
二极管阵列的正向端分别由COL1-COL8端口控制,负向端通过端口ROW1-ROW8控制。
在驱动某个点阵点点亮时,需要同时控制该发光二极管正端接高电平,负端接低电平即可。
例如:
要使得COL4和ROW4交点处二极管点亮,则需要在端口COL端输入数据:
00001000(08H),在ROW端输入:
00001000(08H)。
图4.48×8点阵内部电路
4.3.1.2串行输入并行输出移位寄存器74164功能
如图所示为74164的引脚图,CLEAR为清零端,CLOCK为时钟脉冲输入端,A、B端口为串行输入数据引脚,Q0—Q7为数据输出引脚。
从真值表可以看出,CLEAR为逻辑低电平时,无论其他引脚电平信号如何,从QA-QH端口输出均为低电平,实现输出清零。
A、B输入信号为相与的关系,相与后的结果送入内部RS触发器。
在CLOCK脉冲信号的上升沿,采样输入脚A、B相与后的结果,作为内部RS触发器的输入信号,根据输入数据触发输出,从QA端口输出。
在QA端口输出更新数据时,QB端口输出数据为QA端口更新前的QAn,QC端口输出数据为QBn,依次类推。
图4.574164引脚图
图4.674164内部电路
以如下时序图为例说明:
在图中标注的时钟脉冲1时刻,A端口输入为高电平,B端口输入为逻辑1,在CLOCK上升沿,采样输入信号,经过内部RS触发器,在QA端口输出逻辑1,此时,QB输出为QA更新前QAn,更新前QAn为逻辑0,因此,QB输出为0,QC输出为QBn,QD输出为QCn,依此类推,QH输出为QGn,输出均为0。
在图中标注的时钟脉冲1-8时刻,从A端口串行输入的数据为11010000,从B端口输入数据为11111111逻辑1,AB相与后输入内部RS触发器的串行数据为:
11010000。
经过8个时钟脉冲后,从第八个时钟脉冲上升沿后QA-QH引脚电平可以看出,该串行数据从QA-QH端口并行输出,即从QH-QA输出电平为:
11010000。
从而,实现了将串行输入数据并行输出的功能。
图4.774164时序图
4.3.2程序分析
主程序主要包括系统初始化、中断向量初始化、设置GPIO端口、控制数据传输几个步骤。
4.3.2.1设置GPIO端口的配置函数
voidGpio_select(void)
{EALLOW;
GpioMuxRegs.GPBMUX.all=0x0000;//设置B组端口为GPIO功能
GpioMuxRegs.GPBDIR.all=0xFFFF;//设置B组端口为输出端口
GpioMuxRegs.GPFMUX.all=0x0000;//设置F组端口为GPIO功能
GpioMuxRegs.GPFDIR.all=0xFFFF;//设置F组端口为输出端口
EDIS;}
需要注意:
EALLOW——
在DSP28_Device.h头文件中,通过“#defineEALLOWasm("EALLOW")”在C语言主函数中嵌入汇编语言指令,汇编指令“EALLOW”其含义为开放存储器映像寄存器,设置该命令后,可以对MMR内容进行修改。
当需要配置或修改MMR内容时,必须先写入EALLOW汇编指令。
反之,如果不首先写入EALLOW汇编指令,无法完成对相应MMR内容的修改。
EDIS:
为结束修改MMR的汇编命令。
当MMR配置完成后,需要写入该命令。
4.3.2.2控制数据串行输出函数
voidsendto1(unsignedcharkdab)
{unsignedchari;
CLK1=0;//控制时钟脉冲引脚输出设置为低电平
for(i=0;i<8;i++)//经过八个时钟脉冲控制将八位串行数据输出
{
if((kdab&0x01)==0x01)//判别输出数据
{
DINC=1;//如果输出数据为1,将数据送入DINC输出
}
elseDINC=0;//如果输出数据为0,将数据送入DINC输出
CLK1=1;//时钟引脚设置输出高电平
CLK1=0;//时钟引脚恢复为低电平,通过这两个命令,
//在CLK1脚模拟输出一个时钟脉冲信号,将
//串行端口数据输出一位。
kdab=kdab>>1;//数据右移,提取下一位串行数据
}
}
74164为串行输入/并行输出移位寄存器,控制点阵的数据需要从DSP的gpio端口串行输出。
为满足74164工作时序,采用GPIO端口模拟74164的工作时序。
从DINC输出串行输出数据,同时,在CLK1脚模拟控制脉冲信号。
图4.8串行数据输出控制
串行数据传输函数如上所示。
函数变量dab为需要传输的串行数据。
例如:
需要传输的数据dab为11110011(F3H),如下图所示。
通过变量dab同二进制数0x01相与,将要传输数据的最低位取出。
kdab&0x01结果为1时,则表示传输数据的最低位1。
然后,将判别后的数据送入DINC即GPIOF0端口,经过硬件电路连接,从而传到U1的74164的A端口。
然后,在程序中应用“CLK1=1;CLK1=0;”命令,将CLK1即GPIOF2模拟产生时钟脉冲信号,根据74164时序图,在时钟上升沿将送到A端口的数据移位输出。
之后,将传输数据右移位,判别次低位数据,kdab&0x01结果为1时,则表示传输数据的最低位1,kdab&0x01结果为0时,则表示传输数据的最低位0。
模拟产生脉冲,控制数据移入74164。
经过8次循环,则将8位数据串行输出到74164的端口,并行输出到输出端口。
4.3.2.3输出字符与字模阵列
图4.9字模提取软件
在点阵模块中字符的显示,应用字模生成软件获得显示字符的字模,采用动态扫描的控制方式
显示。
以在点阵模块显示字符“中”为例,首先采用字模提取软件获得字符的字模。
“中”字的字模组合为“10H,FEH,92H,FEH,10H,10H,10H,10H”。
在控制显示时,采用动态扫描的显示方式。
首先将字模中二进制数10H送入点阵模块的行扫描数据输入端口,然后在列扫描线上输出控制第一行点阵二极管点亮的数据“01111111”,则点阵中第一行的第四个二极管点亮,显示“中”字上面的一点。
接下来,将“FEH”送入点阵模块的行扫描数据输入端口,然后在列扫描线上输出控制第二行点阵二极管点亮的数据“10111111”,此时,第二行的1-7二极管点亮,显示出“中”字的上面一横,之前第一行的第四个二极管灭。
继续,行端口输入“92H”,列端口输入控制第三行二极管点亮的控制信号“11011111”,于是,在第三行上1、4、7二极管亮,其他行灭。
依次类推,直到第八行显示。
在控制显示中,每一行逐次轮回显示,由于人本身有的视觉暂留效应,我们只要适当控制每一行的显示延时,就可以将要显示的字符“中”字动态的显示在点阵模块中。
在编写程序中,我们采用数组数组dispdata[]存放行值,用数组dispbit[]存放列值。
dispdata[8]={0x10,0xFE,0x92,0xFE,0x10,0x10,0x10,0x10},dispbit[8]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe},用两个函数sendto1(dispbit[])和sendto2(dispdata[])分别发送数据,由此显示出字模。
调整延时程序——
voidDELAY()
{unsignedlongk,j;
for(k=0;k<10;k++)
for(j=0;j<100;j++);
}
由于扫描速度很快,扫描8列的数据在人眼看来是同时的,所以就可以看到8_8LED字模中显示的字模。
4.3.3参考主程序:
#include"DSP28_Device.h"
#include"DSP28_Globalprototypes.h"
/*****************************************************************************端口GPIOF0用DINA表示,“#define”为宏定义,以下程序中用字符“DINA”代表成员变量GpioDataRegs.GPFDAT.bit.GPIOF0,增加程序的可读性。
其他端口定义用法相同。
***************************************************************************/
#defineDINAGpioDataRegs.GPFDAT.bit.GPIOF0
#defineDINBGpioDataRegs.GPFDAT.bit.GPIOF1
#defineCLK2GpioDataRegs.GPFDAT.bit.GPIOF2
#defineCLEAR2GpioDataRegs.GPFDAT.bit.GPIOF3
#defineDINCGpioDataRegs.GPBDAT.bit.GPIOB0
#defineDINDGpioDataRegs.GPBDAT.bit.GPIOB1
#defineCLK1GpioDataRegs.GPBDAT.bit.GPIOB2
#defineCLEAR1GpioDataRegs.GPBDAT.bit.GPIOB3
/********程序中引用的函数定义**************/
voiddelay_loop(void);//点阵动态显示控制的延时程序
voidGpio_select(void);//GPIO端口设置程序
voidsendto1(unsignedcharkdab);//串行数据输出函数,输出行扫描数
voidsendto2(unsignedchardat);//串行数据输出函数,输出列扫描数
voidDELAY(void);
/**************定义变量数组*****************/
unsignedchardispdata[8]={0x10,0xFE,0x92,0xFE,0x10,0x10,0x10,0x10};
//显示字符“中”字的行扫描数组
unsignedchardispbit[8]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe}
//显示字符“中”字的列扫描数组
unsignedcharkdab;
unsignedcharkdat;
/*************************主程序************************/
voidmain(void)
{unsignedchari;
InitSysCtrl();//系统初始化函数
InitPieCtrl();//初始化PIE模块到默认状态
InitPieVectTable();
Gpio_select();//设置端口函数
/*************************初始化74164各控制引脚**************************/
CLEAR2=0;//74164进行清零操作
CLEAR1=0;//74164进行清零操作
CLEAR2=1;//74164复位
CLEAR1=1;//74164复位
CLK1=1;//74164的CLOCK引脚置为高电平
CLK2=1;//74164的CLOCK引脚置为高电平
DINA=1;//74164数据输入端口置为高电平
DINB=1;//74164数据输入端口置为高电平
DINC=1;//74164数据输入端口置为高电平
DIND=1;//74164数据输入端口置为高电平
while
(1)
{
sendto1(dispbit[0]);
sendto2(dispdata[0]);
DELAY();
sendto1(dispbit[1]);
sendto2(dispdata[1]);
DELAY();
sendto1(dispbit[2]);
sendto2(dispdata[2]);
DELAY();
sendto1(dispbit[3]);
sendto2(dispdata[3]);
DELAY();
}
}
/***********************GPIO端口配置函数***************************/
voidGpio_select(void)
{EALLOW;
GpioMuxRegs.GPBMUX.all=0x0000;//设置B组端口为GPIO功能
GpioMuxRegs.GPBDIR.all=0xFFFF;//设置B组端口为输出端口
GpioMuxRegs.GPFMUX.all=0x0000;//设置F组端口为GPIO功能
GpioMuxRegs.GPFDIR.all=0xFFFF;//设置F组端口为输出端口
EDIS;}
/****************行扫描数据串行输出函数***************************/
voidsendto1(unsignedcharkdab)
{unsignedchari;
kdab=dab;
CLK1=0;//控制时钟脉冲引脚输出设置为低电平
for(i=0;i<8;i++)//经过八个时钟脉冲控制将八位串行数据输出
{
if((kdab&0x01)==0x01)//判别输出数据
{
DINC=1;//如果输出数据为1,将数据送入DINC输出
}
elseDINC=0;//如果输出数据为0,将数据送入DINC输出
CLK1=1;//时钟引脚设置输出高电平
CLK1=0;//时钟引脚恢复为低电平,通过这两个命令,
//在CLK1脚模拟输出一个时钟脉冲信号,将
//串行端口数据输出一位。
kdab=kdab>>1;//数据右移,提取下一位串行数据
}
}
/****************列扫描数据串行输出函数***************************/
voidsendto1(unsignedcharkdab)
{unsignedchari;
kdab=dab;
CLK1=0;//控制时钟脉冲引脚输出设置为低电平
for(i=0;i<8;i++)//经过八个时钟脉冲控制将八位串行数据输出
{
if((kdab&0x01)==0x01)//判别输出数据
{
DINC=1;//如果输出数据为1,将数据送入DINC输出
}
elseDINC=0;//如果输出数据为0,将数据送入DINC输出
CLK1=1;//时钟引脚设置输出高电平
CLK1=0;//时钟引脚恢复为低电平,通过这两个命令,
//在CLK1脚模拟输出一个时钟脉冲信号,将
//串行端口数据输出一位。
kdab=kdab>>1;//数据右移,提取下一位串行数据
}
}
=====================================================================
======================================================================
(注:
可编辑下载,若有不当之处,请指正,谢谢!
)