OpenVINOTM,给你看得见的未来!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 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 跳转至

回复

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