这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界» 论坛首页» 嵌入式开发» FPGA» DSP入门学习笔记2——从流水灯到GPIO

共2条 1/1 1 跳转至

DSP入门学习笔记2——从流水灯到GPIO

专家
2014-11-06 09:59:08 打赏
流水灯之于硬件学习,犹如Hello World之于软件学习。
一个简单地用有限状态机实现GPIO控制的程序,翼志的开发板配了个往复流水灯的实例,略作修改,屏蔽了不用的管脚配置…… 流水灯情况工作良好,大概是最简单的GPIO控制了吧。
硬件上与单片机并无差异,六盏共阳极LED接在F2812的GPIOA0~ GPIOA5上。 流水灯实现程序如下:
content of flowled.c
//包含头文件 #include "DSP28_Device.h" #include "DSP28_Globalprototypes.h" #define ShiftDir 0 //定义流水的方向 #define Timelag 15 // 定义 状态切换的时间间隔
unsigned int MuxValue=0; unsigned int DirValue=0; unsigned int QualValue=0;
//声明延时函数、及GPIO功能选择函数 void delay_loop(void); void Gpio_select(void);
void main(void) { unsigned int DisplayBuffer = 0x0001;//初值寄存器,设初始时点亮一盏小灯 unsigned char DelayTimes;//延时时间控制 unsigned char SFTDIR = ShiftDir; //环移方向 //初始化系统控制寄存器 InitSysCtrl();
// 禁止所有 CPU中断: DINT; IER = 0x0000; IFR = 0x0000;
// 将Pie控制寄存器初始化为默认值: InitPieCtrl(); InitPieVectTable();
// Run GPIO test MuxValue= 0x0000; // 配置 GPIO Mux寄存器为I/O DirValue= 0xFFFF; // GPIO 方向寄存器值,全部管脚设为输出 QualValue= 0x0000; // 输入采样值,在该例中没用,所以全部管脚qual设置为0 Gpio_select(); // Toggle I/Os using DATA register for ever while(1) { //将DisplayBuffer的值取反后送GPIO——共阳极LED GpioDataRegs.GPADAT.all = ~DisplayBuffer;
if(SFTDIR==1) { DisplayBuffer <<= 1; //LED状态左移 if(DisplayBuffer == 0x0040)DisplayBuffer = 0x0001; //恢复初值,实现环移 } else { if(DisplayBuffer == 0x001)DisplayBuffer = 0x0040; //恢复初值,实现环移
DisplayBuffer >>= 1; //LED状态右移 }
for(DelayTimes=0;DelayTimes { delay_loop(); } } }
void delay_loop() { //简单而粗暴的实现软延时 long i; for (i = 0; i < 400000; i++) {} }
void Gpio_select(void) { EALLOW; //允许访问保护区寄存器 //初始化全部GPIO的MUX,其实该例中只需要初始化GPAMUX即可,这里0表示全部设为输出 GpioMuxRegs.GPAMUX.all=MuxValue; //GpioMuxRegs.GPBMUX.all=MuxValue; //GpioMuxRegs.GPDMUX.all=MuxValue; //GpioMuxRegs.GPFMUX.all=MuxValue; //GpioMuxRegs.GPEMUX.all=MuxValue; //GpioMuxRegs.GPGMUX.all=MuxValue;
//初始化全部GPIO的DIR,其实该例中只需要初始化GPADIR即可 GpioMuxRegs.GPADIR.all=DirValue; // GPIO PORTs as output //GpioMuxRegs.GPBDIR.all=DirValue; // GPIO DIR select GPIOs as output //GpioMuxRegs.GPDDIR.all=DirValue; //GpioMuxRegs.GPEDIR.all=DirValue; //GpioMuxRegs.GPFDIR.all=DirValue; //GpioMuxRegs.GPGDIR.all=DirValue;
//初始化全部GPIO的QUAL,其实该例中我怀疑不用初始化也没问题 GpioMuxRegs.GPAQUAL.all=QualValue; // Set GPIO input qualifier values //GpioMuxRegs.GPBQUAL.all=QualValue; //GpioMuxRegs.GPDQUAL.all=QualValue; //GpioMuxRegs.GPEQUAL.all=QualValue;
EDIS; //使能保护 }
======================================EOF===================================================

调试过程没有任何阻力…… 呵呵,这就是修改例程的好处。

从例程中大致看出2812的GPIO有A到G 六组,但并非全部都是16位的,具体每组需要对应着数据手册里的硬件管脚说明来看,这里开发板把小灯接在GPIOA0~5还有个好处,日后可以通过PWM输出做渐变的效果。
官方手册上关于GPIO的内部功能结构用一张图来描述

左上角的矩形里包含了GPIO全部相关寄存器
GPIOxMUX.bit : 0——GPIO , 1——第二功能
GPIOxDIR.bit :0——输入,1——输出
GPIOxQUAL只有低8位有用,用来定义输入采样周期,数值为n(n<>0)时,采样周期为系统时钟的2*n倍;取0时为与系统时钟同步采样

这些寄存器都是受EALLOW保护的
数据(位操作)寄存器是不受EALLOW保护的
GPIOxDAT:GPIO的数据锁存器,与单片机的Px原理大致相同;
GPIOxSET.bit : 置位寄存器,为1时相应位对应的外部管脚被置高电平,为0没用;
GPIOxCLEAR.bit:清零寄存器, 为1时相应位对应的外部管脚被置低电平,为0没用;
GPIOxTOGGLE.bit:位翻转寄存器,为1时相应位对应的外部管脚电平状态取反,为0没用;


验证该实例时,只用了前面4个寄存器,后面3个的功能还没试验。
显然,所有控制都是以位为单位的……
如果需要整字赋值,如实例中一般GPIOxXXXX.all

目前还有一处没想明白的地方:在通用管脚输出状态下,既然 给
GPIOxDAT赋值即可改变该管教的状态,为啥还要SET和CLEAR两个寄存器?难道是给第二功能的管脚状态初始化用?

实践证明,使用TOGGLE的好处是,闪烁灯效果不再需要中间变量取反后重赋值来实现。
GpioDataRegs.GPATOGGLE.all=0xFFFF; //可以 实现A口全部小灯闪烁效果


用置位指令和清零指令的好处暂时没感受到,不过流水灯也可以这么实现

if(SFTDIR==1){
DisplayBuffer <<= 1; //LED状态左移 if(DisplayBuffer == 0x0040)DisplayBuffer = 0x0001; //恢复初值,实现环移 GpioDataRegs.GPACLEAR.all = DisplayBuffer; GpioDataRegs.GPASET.all = ~DisplayBuffer; } else {
if(DisplayBuffer == 0x001)DisplayBuffer = 0x0040; //恢复初值,实现环移 DisplayBuffer >>= 1; //LED状态右移 GpioDataRegs.GPACLEAR.all = DisplayBuffer; GpioDataRegs.GPASET.all = ~DisplayBuffer;



关键词: 2812 dsp 流水灯 gpio

高工
2021-02-26 16:54:21 打赏
2楼

谢谢分享


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册]