DSP简单例程
- 格式:docx
- 大小:18.39 KB
- 文档页数:3
一个简单的dsp C语言例子开发平台: CCS集成开发环境通过这个简单的例子, 可以大致了解用C语言开发dsp程序的原理。
程序要求: 用C语言编写产生正弦调幅波信号的源程序;正弦调幅波的公式在离散域中的表示:y(n) = (1 + M*sin(2 * PI * fb / fs * n)) * sin(2 * PI * fa / fs * n);编写文件1.sin_am.c#include<stdio.h>#include<math.h>#define TRUE 1#define pi 3.1415926536int y[500],i;float M;void main(){puts("amplitude modulation sinewave example started.\n");M = 50;for(i = 0; i < 500; i++)y[i]= 0;while(TRUE){for(i = 0; i < 500; i++)y[i]=(int)((1 + M / 100 * sin(i * 2 * pi * 20 / 4000))* sin(i * 2 * pi * 200 / 4000)* 16384);puts("program end");}}2.sin_am_v.asm (reset vector file).title "sin_am_v.asm".sect ".vectors".ref _c_int00RESET:B _c_int00.end..3.sin_am.cmdsin_am.objsin_am_v.obj-m sin_am.map-o sin_am.outMEMORY{PAGE 0:EPROG: origin = 0x1400, len = 0x7c00 VECT: origin = 0xff80, len = 0x80PAGE 1:USERREGS: origin = 0x60, len = 0x1c IDATA: origin = 0x80, len = 0x3000 }SECTIONS{.vectors:>VECT PAGE 0.text:>EPROG PAGE 0.cinit:>EPROG PAGE 0.bss:>IDATA PAGE 1.const:>IDATA PAGE 1.switch:>IDATA PAGE 1.system:>IDATA PAGE 1.stack:>IDATA PAGE 1}"*.cmd"文件说明:链接命令文件是实现对段的存储空间位置的定位, C语言程序中常用已初始化和未初始化段如下:已初始化段包括:.init 存放C程序中的变量的初值和常量, 放在ROM和RAM 中均可, 一般属于PAGE 0.const 存放C程序中的字符常量、浮点常量和用const声明的常量, 放在ROM和RAM中均可, 一般属于PAGE 1.text 存放C程序代码, 放在ROM和RAM中均可, 一般属于PAGE 0.switch 存放C程序中的语句的跳针表, 放在ROM和RAM中均可, 一般属于PAGE 0未初始化段包括:.bss 为C程序中的全局和静态变量保留存储空间, 一般存放于RAM中, 属于PAGE 1.stack 为C程序系统堆栈保留存储空间, 用于保存返回地址、函数间的参数传递、存储局部变量和保存中间结果, 一般存放于RAM中, 属于PAGE 1.sysmem 用于C程序中malloc、calloc和realloc函数动态分配存储空间, 一般存放于RAM中, 属于PAGE 14.vary_M.gelmenuitem "Myfunctions"slider vary_M(0, 100, 10, 1, Amount_of_modulation){M = Amount_of_modulation;}该文件用于调试的时候可随意改变变量M的值, 该文件通过file->load GEL File添加到工程中, 调试的时候可选择GEL->My Functions->vary_M来打开vary_M滑动条组件。
不知道你学过单片机没有。
37个寄存器是R1-R16.(当然,里面有很多是分几个模式的,所以总共有37个)类似于单片机的R0-R7.GPXCON,GPXDAT等等是另外的寄存器,应该叫,特殊功能寄存器,类似于单片机的P0,P1,TCON,等等。
GPXCON:是X管脚的控制寄存器,控制它们的模式,比如输出模式,输入模式……GPXDAT:是X管脚的数据寄存器,存储它们的数据,比如:在输出模式中,想在X管脚输出什么数据,就在这个寄存器里写入什么数据,在输入模式中,这个寄存器中存储的就是外部输入的数据。
手把手教你找GPIO寄存器IODIR 定义手把手教你找寄存器定义一直就很纳闷,没有一个向c8051f410.h的头文件定义特殊功能寄存器,找不见定义,使用起来就无从下手,心里总是不舒坦;从网上看了一些帖子,都说就是在头文件里(我也是这么认为的,肯定要有定义的,不然无法调用)StartUp{………..……….GEL_MapAdd(0x3400u,2,0x0400u,1,1); /* GPIO 1KW */………..}这段映射0x3400u 为GPIO空间,其实只是表示这段i/o空间可读可写;下面是我一步一步地追踪,这些都是要用到的宏定义;#define PREG16(addr) (*(volatile ioport Uint16*)(addr)) 从一个ioport Uint16*类型的地址中取出地址内容,就是IODIR寄存器的值了#define _GPIO_IODIR_ADDR (0x3400u) //定义了IO地址常量#define _GPIO_IODIR PREG16(_GPIO_IODIR_ADDR) //得到寄存器的地址#define _IODIR _GPIO_IODIR 定义了 _IODIR 常量#define GPIO_ADDR(Reg) _GPIO_##Reg##_ADDR 两个变量合并#define _PREG_SET(PregAddr, Val) PREG16(PregAddr) = (Uint16)Val#define GPIO_RSET(Reg,Val) _PREG_SET(GPIO_ADDR(##Reg),Val)从这个宏定义开始1:GPIO_RSET(IODIR,1)这句很明显了,把IODIR寄存器的值置12:_PREG_SET(GPIO_ADDR(##IODIR),1)利用这两个宏#define GPIO_RSET(Reg,Val) _PREG_SET(GPIO_ADDR(##Reg),Val)#define GPIO_ADDR(Reg) _GPIO_##Reg##_ADDR分解的到a:GPIO_ADDR(IODIR) _GPIO_##Reg##_ADDR_GPIO_ IODIR _ADDRb:_PREG_SET(_GPIO_ IODIR _ADDR,1)3:接下来#define _PREG_SET(PregAddr, Val) PREG16(PregAddr) = (Uint16)ValPREG16(_GPIO_ IODIR _ADDR) =1;4::#define PREG16(addr) (*(volatile ioport Uint16*)(addr)) **(_GPIO_ IODIR _ADDR) = 1;5:这句就简单了*(0x3400u) = 1;一步一步顺藤摸瓜,总算摸到;但我们的问题,还是没讲清楚;究竟IODIR 是在哪里定义的呢?开始我也很迷惑,仔细想想后,惶然大悟,快乐!!问题出在,这些都是宏语句,执行编译前,就已经把GPIO_RSET(IODIR,1) 翻译成*(0x3400u) = 1;编译器不认识IODIR ,而IODIR在直到#define GPIO_ADDR(Reg) _GPIO_##Reg##_ADDR 两个变量合并前就是个字符串,连个常量都算不上(不知道这么说确切不,完全是因为它在语句的位置,赋予了它意义)跟单片机类比 SFR IODIR = 0X3400;编译器绕了这么一大圈,其实做得工作太简单了,究竟为什么这么做,我还没来得及想。
通用定时器1、通用定时器有四个中断:A、通用定时器1上溢中断B、通用定时器下溢中断C、通用定时器比较中断D、通用定时器周期中断这四个中断标志位在EV A中断标志寄存器A(EV AIFRA)中,这四个中断的使能位在EV A 屏蔽寄存器EV AIMRA中设置。
2、通用定时器有三个16位的和定时比较有关的寄存器:A、通用定时器计数寄存器TXCNTB、通用定时器周期寄存器TxPRC、通用定时器比较寄存器TXCMPR通用定时器计数寄存器TxCNT根据通用定时器的时钟和计数模式开始计数,不停的和周期寄存器和比较寄存器从而产生中断或者各种事件。
当工作在定时器的模式时,TxCNT得值和TxPR中设置的值比较,当比较匹配后的一个时钟后,产生相应的事件当工作在比较的模式时,TxCNT得值和TxCMPR中设置的值比较,当比较匹配后的一个时钟后,产生相应的比较事件TxPR和TxCMPR都是带有影子寄存器的,在一个周期的任何时刻都可以对这两个寄存器进行读写,读写的是他们的影子寄存器。
对于TxCMPR,只有当TxCON寄存器指定的特定条件满足时,影子寄存器中的值才加载到比较寄存器中;对于周期寄存器,只有当计数寄存器为0时,影子寄存器的值才能重新加载到周期寄存器。
3、通用定时器的计数模式通用定时器有四种计数模式A、停止/保持吧、模式(TxCON.TMODE1~TMODE0=00)B、连续增计数模式(TxCON.TMODE1~TMODE0=01)C、定向增/减计数模式(有外部引脚决定,xCON.TMODE1~TMODE0=11D、连续增减计数模式(TxCON.TMODE1~TMODE0=10)通过定时器控制寄存器TxCON的12~11位决定,4、时钟可以是外部时钟也可以是内部时钟,一般用内部时钟,内部时钟是HSPCLK经过预分频后得到的。
由TxCON得5~4位决定,TxCON。
TCLKS1~TCLKS0=00选择内部时钟;预分频由TxCON得10~8位决定,CLK=HSPCLK/2的TxCON。
1.led1 1s啥闪烁led3 1.5s闪烁#include "DSP28_Device.h"#include "ext_inf.h"unsigned int Led_Flag;interrupt void ISRTimer2(void);void main(void){/*初始化系统*/InitSysCtrl();/*关中断*/DINT;IER = 0x0000;IFR = 0x0000;Led_Flag = 0;/*初始化PIE*/InitPieCtrl();/*初始化PIE中断矢量表*/InitPieVectTable();/*初始化外设*/InitPeripherals();EALLOW;PieVectTable.TINT2 = &ISRTimer2;EDIS;/*设置CPU*/ConfigCpuTimer(&CpuTimer2, 150, 500000);StartCpuTimer2();/*开中断*/IER |= M_INT14;EINT; // Enable Global interrupt INTMERTM; // Enable Global realtime interrupt DBGM for(;;);}interrupt void ISRTimer2(void){CpuTimer2.InterruptCount++;if(CpuTimer2.InterruptCount==1){*LED3 = 0;//此行添加断点LED1_ON;}if(CpuTimer2.InterruptCount==2){*LED3 = 0;//此行添加断点LED1_ON;}if(CpuTimer2.InterruptCount==3){*LED3 = 0;//此行添加断点LED1_OFF;}if(CpuTimer2.InterruptCount==4){*LED3 = 1;//此行添加断点LED1_OFF;}if(CpuTimer2.InterruptCount==5){*LED3 = 1;//此行添加断点LED1_ON;}if(CpuTimer2.InterruptCount==6){*LED3 = 1;//此行添加断点LED1_ON;}if(CpuTimer2.InterruptCount==7){*LED3 = 0;//此行添加断点LED1_OFF;}if(CpuTimer2.InterruptCount==8){*LED3 = 0;//此行添加断点LED1_OFF;}if(CpuTimer2.InterruptCount==9){*LED3 = 0;//此行添加断点LED1_ON;}if(CpuTimer2.InterruptCount==10){*LED3 = 1;//此行添加断点LED1_ON;}if(CpuTimer2.InterruptCount==11){*LED3 = 1;//此行添加断点LED1_OFF;}if(CpuTimer2.InterruptCount==12){*LED3 = 1;//此行添加断点LED1_OFF;}}2.AD转换每次采集8个信号,去掉最高最低,取平均值#include <math.h>#include "DSP28_Device.h"#include "comm.h"///////////////////////////////////////////////////////////////////#define SAMPLERATE 4unsigned int SampleRate;unsigned int SampleLong=1024;///////////////////unsigned int i,j;unsigned int Ad_data[1536]={0};int q[8]={0};unsigned int k=0,p=0,temp;float s=0;//////////////////unsigned int convcount = 0;volatile unsigned int adconvover =0;// Prototype statements for functions found within this file.interrupt void ISRTimer2(void);interrupt void ad(void);void sequence(int a[],int n);/*****************************************************************************/ void main(void){/*初始化系统*/InitSysCtrl();#if SAMPLERATE==1SampleRate =ADSAMPL8K;#endif#if SAMPLERATE==2SampleRate =ADSAMPL44K;#endif#if SAMPLERATE==3SampleRate =ADSAMPL96K;#endif#if SAMPLERATE==4SampleRate =ADSAMPL16K;#endif/*关中断*/DINT;IER = 0x0000;IFR = 0x0000;/*初始化PIE中断*/InitPieCtrl();/*初始化PIE中断矢量表*/InitPieVectTable();//初始化cputimerInitCpuTimers();/*设置中断服务程序入口地址*/EALLOW; // This is needed to write to EALLOW protected registersPieVectTable.TINT2 = &ISRTimer2;PieVectTable.ADCINT = &ad;EDIS; // This is needed to disable write to EALLOW protected registers/*开中断*/IER |= M_INT1;//ADC中断EINT; // Enable Global interrupt INTMERTM; // Enable Global realtime interrupt DBGM/*启动AD采样*//*AD采样率*/adconvover=0;switch( SampleRate){case ADSAMPL8K: //采样率为8kDINT;/*设置CPU*/ConfigCpuTimer(&CpuTimer2, 150, 125);StartCpuTimer2();/*开中断*/IER |= M_INT14;EINT;InitAdc();SampleRate = 0;break;case ADSAMPL44K: //采样率为44kDINT;/*设置CPU*/ConfigCpuTimer(&CpuTimer2, 150, 22);StartCpuTimer2();/*开中断*/IER |= M_INT14;EINT;InitAdc();SampleRate = 0;break;case ADSAMPL16K: //采样率为16kDINT;ConfigCpuTimer(&CpuTimer2,150,62);StartCpuTimer2();IER |= M_INT14;EINT;InitAdc();SampleRate = 0;break;case ADSAMPL96K: //采样率为96kDINT;/*设置CPU*/ConfigCpuTimer(&CpuTimer2, 150, 10);StartCpuTimer2();/*开中断*/IER |= M_INT14;EINT;InitAdc96k();SampleRate = 0;break;default:break;}for(;;){if (adconvover==1){adconvover=0;}}}interrupt void ad(void){IFR=0x0000;PieCtrl.PIEACK.all=0xffff;q[k] = AdcRegs.RESULT0;k++;{k=0;sequence(q,7);for(p=1;p<7;p++)s=s+q[p];s=s/6;Ad_data[convcount]=s;s=0;convcount++;}if (convcount==(SampleLong+SampleLong/2)){convcount=0;adconvover=1;//接满标志}}interrupt void ISRTimer2(void){AdcRegs.ADC_ST_FLAG.bit.INT_SEQ1_CLR=1;AdcRegs.ADCTRL2.bit.SOC_SEQ1=1;}void sequence(int a[],int n){int i=0;int j=0;int temp=0;for(i=0;i<n;i++){for(j=i+1;j<=n;j++){if(a[i]>a[j]){temp=a[i];a[i]=a[j];a[j]=temp;}}}}#include "DSP28_Device.h"#define a 0x0003#define b 0x000c#define c 0x0030#define d 0x00c0/*定义扩展总线存储器空间页地址寄存器地址为0x004020*/ volatile unsigned int* p_ceselect=(volatile unsigned int *)0x004020; /*定义交通灯IO口的地址为0x80000*/volatile unsigned int* p_iodisable=(volatile unsigned int *)0x080007; //子函数声明interrupt void eva_timer1_isr(void);//全局中断计数变量int Direct1=0;int Direct2=0;Uint32 EvaTimer1InterruptCount;Uint32 i,j=0;Uint32 uart_sendtype;Uint32 Sci_VarRx[100];Uint32 flag=2;Uint32 Send_Flag;Uint32 speed=0xffff;Uint32 num=0;Uint32 NU=0;Uint32 table0[4]={0,0,0,0};Uint32 table1[4]={d,b,c,a};Uint32 table2[4]={a,c,b,d};Uint32 Q[5]={125,62,42,31,25};Uint32 q=0;Uint32 p=4;void main(void){/*初始化系统*/InitSysCtrl();/*关中断*/DINT;IER = 0x0000;IFR = 0x0000;//*p_ceselect =0x6 ;//打开ce3空间for(i=0;i<0x100;i++);*p_iodisable =0x1;//IO空间始能for(i=0;i<0x100;i++);/*初始化PIE控制寄存器*/InitPieCtrl();/*初始化PIE矢量表*/InitPieVectTable();/*初始化EV*/InitEv();InitSci();for(i = 0; i < 100; i++){Sci_VarRx[i] = 0;}i = 0;j = 0;Send_Flag = 0;//重新分配中断服务的中断向量EALLOW;PieVectTable.T1PINT = &eva_timer1_isr; //定时器1计数中断EDIS;//初始化变量EvaTimer1InterruptCount = 0;// 使能PIE 组 2 中断4 -- T1PINTPieCtrl.PIEIER2.all = M_INT4;// 使能CPU中断IER |= M_INT2 ;EINT;ERTM;for(;;){}}/**********************************************///EVGP1周期中断/**********************************************/interrupt void eva_timer1_isr(void){j++;if(j==Q[p]){j=0;EvaTimer1InterruptCount++;if(EvaTimer1InterruptCount==4){EvaTimer1InterruptCount=0;num++;}if(q==0)EvaRegs.ACTRA.all=table2[EvaTimer1InterruptCount]; if(q==1)EvaRegs.ACTRA.all=table1[EvaTimer1InterruptCount];}//使能中断EvaRegs.EV AIMRA.bit.T1PINT = 1;//清除中断标志EvaRegs.EV AIFRA.all = BIT7;//中断应答接收更多的PIE 组2的中断PieCtrl.PIEACK.all = PIEACK_GROUP2;}4.直流电机调速#include "DSP28_Device.h"int m=1;void xnitgpio(){EALLOW;GpioMuxRegs.GPEMUX.bit.XINT2_ADCSOC_GPIOE1=1;GpioMuxRegs.GPEQUAL.BIT.QUALPRD=0x0ff;XIntruptRegs.XINT2CR.bit.ENABLE=1;XIntruptRegs.XINT2CR.bit.POLARITY=0;EDIS;}void InitEvA(void){//设置GPIOEALLOW;GpioMuxRegs.GPAMUX.all=0x00ff;//GpioMuxRegs.GPAMUX.all=0x00fe;//GpioMuxRegs.GPADIR.bit.GPIOA0=1;//GpioDataRegs.GPADAT.bit.GPIOA0=1;EDIS;// 初始化定时器控制寄存器(EV A)EvaRegs.GPTCONA.all = 0;//设置定时器1// 设置定时器1的周期和比较;if(m==0){EvaRegs.T1PR = 0x1d4c;//(7500) 10khz; // 周期EvaRegs.T1CMPR = 0x0000;} //0%if(m==1){EvaRegs.T1PR = 0x1d4c;//(7500) 10khz; // 周期EvaRegs.T1CMPR = 0x15f9;} //75%if(m==2){EvaRegs.T1PR = 0x1d4c;//(7500) 10khz; // 周期EvaRegs.T1CMPR = 0x1770;} //80%if(m==3){EvaRegs.T1PR = 0x1d4c;//(7500) 10khz; // 周期EvaRegs.T1CMPR = 0x18e7;} //85%if(m==4){EvaRegs.T1PR = 0x1d4c;//(7500) 10khz; // 周期EvaRegs.T1CMPR = 0x1a5e;} //90%if(m==5){EvaRegs.T1PR = 0x1d4c;//(7500) 10khz; // 周期EvaRegs.T1CMPR = 0x1bd5;} //95%if(m==6){EvaRegs.T1PR = 0x1d4c;//(7500) 10khz; // 周期EvaRegs.T1CMPR = 0x1d4c;} //100%// 中断使能EvaRegs.EV AIMRA.bit.T1PINT = 1;EvaRegs.EV AIFRA.bit.T1PINT = 1;// 清除计数寄存器EvaRegs.T1CNT = 0x0000;// 设置定时器控制寄存器//EvaRegs.T1CON.all = 0x1042;EvaRegs.T1CON.all = 0x1040;//连续递增/递减计数,定时器使能,比较使能//设置定时器2// 设置定时器2的周期和比较;EvaRegs.T2PR = 0x1d4c;//0x0fff; // 周期EvaRegs.T2CMPR = 0x000; // 比较// 清除计数寄存器EvaRegs.T2CNT = 0x0000;// 设置定时器控制寄存器//EvaRegs.T2CON.all = 0x1042;EvaRegs.T2CON.all = 0x1040;EvaRegs.EV AIMRB.bit.T2PINT = 1;//定时器2周期中断允许EvaRegs.EV AIFRB.bit.T2PINT = 1;//清除标志//设置T1PWM和T2PWM//比较逻辑驱动T1/T2PWMEvaRegs.GPTCONA.bit.TCOMPOE=1;//EvaRegs.GPTCONA .bit .TCMPOE=1;//定时器1比较其极性设置为高电平有效EvaRegs.GPTCONA .bit .T1PIN =2;//定时器2比较其极性设置为高电平有效EvaRegs.GPTCONA .bit .T2PIN =2;//使能产生PWM1-PWM6的比较功能/*EvaRegs.CMPR1 =0x00c0;EvaRegs.CMPR2 =0x03c0;EvaRegs.CMPR3 =0x0fc0;*///比较方式控制//输出引脚1CMPR1-高有效输出引脚2CMPR1-低有效//输出引脚3CMPR2-高有效输出引脚4CMPR2-低有效//输出引脚5CMPR3-高有效输出引脚6CMPR3-低有效//EvaRegs.ACTRA .all=0x0666;//EvaRegs.DBTCONA.all=0x0Af8;//x/4,死区开,m=2,p=4,t=0.2us // CONA .all=0xA600;}。
Code Composer Studio 教程(二)——开发一个DSP/BIOS程序在此教程中,通过使用DSP/BIOS来优化hello程序。
此教程需要一个目标板,而且不可以用一软件模拟器来实现。
同时,此教程需要CCS的DSP/BIOS部分。
步骤1:创建一个配置文件另一种实现hello程序的方法是使用配有DSP/BIOS API的LOG模块(API——应用程序接口)。
你可以在加载入的程序中使用DSP/BIOS来提供基本的运行时间服务。
API模块使实时DSPs进行最优化。
不同于C库调用如puts(),DSP/BIOS在不暂停目标硬件的情况下进行实时分析。
另外,API代码占用更小的空间,同时比C标准的I/O运行更快。
一个程序可使用一个或更多的DSP/BIOS模块。
在此,修改hello 文件以使用DSP/BIOS API。
为应用DSP/BIOS API,一个程序必须拥有一个程序所使用的定义了DSP/BIOS对象的配置文件。
1)打开项目myhello.mak。
(在D:\han\study2目录下)2)File ——> New ——> DSP/BIOS Config。
3)选择对DSP板的类型,确定。
此时弹出一界面窗口。
4)右击LOG-Event Log Manager,并选择Insert LOG,这样建立一个名为LOG0的LOG对象。
5)右击LOG0,选择Rename,改名为“trace”。
6)File ——> Save。
保存于工作目录下,配置文件名为myhello.cmd。
保存此配置直接产生以下文件:①myhello.cdb:保存配置的设置。
②myhellocfg.cmd:连接器命令文件。
③myhellocfg.s62:汇编语言源文件。
④myhellocfg.h62:包含在myhellocfg.s62中的汇编语言头文件。
尽管这些文件拥有.s62和.h62的扩展名,它们也可应用在TMS320C6701中。
典型dsp处理流程下载温馨提示:该文档是我店铺精心编制而成,希望大家下载以后,能够帮助大家解决实际的问题。
文档下载后可定制随意修改,请根据实际需要进行相应的调整和使用,谢谢!并且,本店铺为大家提供各种各样类型的实用资料,如教育随笔、日记赏析、句子摘抄、古诗大全、经典美文、话题作文、工作总结、词语解析、文案摘录、其他资料等等,如想了解不同资料格式和写法,敬请关注!Download tips: This document is carefully compiled by theeditor.I hope that after you download them,they can help yousolve practical problems. The document can be customized andmodified after downloading,please adjust and use it according toactual needs, thank you!In addition, our shop provides you with various types ofpractical materials,such as educational essays, diaryappreciation,sentence excerpts,ancient poems,classic articles,topic composition,work summary,word parsing,copy excerpts,other materials and so on,want to know different data formats andwriting methods,please pay attention!深入理解典型DSP(数字信号处理)处理流程数字信号处理(Digital Signal Processing,简称DSP)是现代电子技术中的一个重要领域,它在通信、音频、图像、雷达等多个领域都有广泛的应用。
不知道你学过单片机没有。
37个寄存器是R1-R16.(当然,里面有很多是分几个模式的,所以总共有37个)
类似于单片机的R0-R7.
GPXCON,GPXDAT等等是另外的寄存器,应该叫,特殊功能寄存器,类似于单片机的P0,P1,TCON,等等。
GPXCON:是X管脚的控制寄存器,控制它们的模式,比如输出模式,输入模式……GPXDAT:是X管脚的数据寄存器,存储它们的数据,
比如:
在输出模式中,想在X管脚输出什么数据,就在这个寄存器里写入什么数据,
在输入模式中,这个寄存器中存储的就是外部输入的数据。
手把手教你找GPIO寄存器IODIR 定义
手把手教你找寄存器定义
一直就很纳闷,没有一个向c8051f410.h的头文件定义特殊功能寄存器,找不见定义,使用起来就无从下手,心里总是不舒坦;
从网上看了一些帖子,都说就是在头文件里(我也是这么认为的,肯定要有定义的,不然无法调用)
StartUp{
………..
……….
GEL_MapAdd(0x3400u,2,0x0400u,1,1); /* GPIO 1KW */
………..
}
这段映射0x3400u 为GPIO空间,其实只是表示这段i/o空间可读可写;
下面是我一步一步地追踪,这些都是要用到的宏定义;
#define PREG16(addr) (*(volatile ioport Uint16*)(addr)) 从一个ioport Uint16*类型的地址中取出地址内容,就是IODIR寄存器的值了
#define _GPIO_IODIR_ADDR (0x3400u) //定义了IO地址常量
#define _GPIO_IODIR PREG16(_GPIO_IODIR_ADDR) //得到寄存器的地址
#define _IODIR _GPIO_IODIR 定义了 _IODIR 常量
#define GPIO_ADDR(Reg) _GPIO_##Reg##_ADDR 两个变量合并
#define _PREG_SET(PregAddr, Val) PREG16(PregAddr) = (Uint16)Val
#define GPIO_RSET(Reg,Val) _PREG_SET(GPIO_ADDR(##Reg),Val)
从这个宏定义开始
1:GPIO_RSET(IODIR,1)
这句很明显了,把IODIR寄存器的值置1
2:_PREG_SET(GPIO_ADDR(##IODIR),1)
利用这两个宏
#define GPIO_RSET(Reg,Val) _PREG_SET(GPIO_ADDR(##Reg),Val)
#define GPIO_ADDR(Reg) _GPIO_##Reg##_ADDR
分解的到
a:GPIO_ADDR(IODIR) _GPIO_##Reg##_ADDR
_GPIO_ IODIR _ADDR
b:_PREG_SET(_GPIO_ IODIR _ADDR,1)
3:接下来
#define _PREG_SET(PregAddr, Val) PREG16(PregAddr) = (Uint16)Val
PREG16(_GPIO_ IODIR _ADDR) =1;
4::#define PREG16(addr) (*(volatile ioport Uint16*)(addr)) *
*(_GPIO_ IODIR _ADDR) = 1;
5:这句就简单了*(0x3400u) = 1;
一步一步顺藤摸瓜,总算摸到;但我们的问题,还是没讲清楚;
究竟IODIR 是在哪里定义的呢?
开始我也很迷惑,仔细想想后,惶然大悟,快乐!!
问题出在,这些都是宏语句,执行编译前,就已经把GPIO_RSET(IODIR,1) 翻译成*(0x3400u) = 1;
编译器不认识IODIR ,而IODIR在直到
#define GPIO_ADDR(Reg) _GPIO_##Reg##_ADDR 两个变量合并
前就是个字符串,连个常量都算不上(不知道这么说确切不,完全是因为它在语句的位置,赋予了它意义)
跟单片机类比 SFR IODIR = 0X3400;
编译器绕了这么一大圈,其实做得工作太简单了,究竟为什么这么做,我还没来得及想。
总之这个问题已经很明白了;
数字地和模拟地
模拟和数字的概念要搞清楚,模拟是连续的,数字通常就是高低电平信号,之所以模拟地和数字地要分开原因就是担心两总信号之间的干扰。
举个例子说吧,你的耳机是就是由模拟信号来驱动的,它就有一个地,这个地就是模拟地,然后这个地要通过一个磁珠来和你解码芯片的地连接,这样你的输出音质才会好。
是模拟或者数字是由你的后端电路来决定的,而不是你稳压出的电压决定的!!!也就是说你稳压出的电压,可以用在模拟也可以用作数字。