当前位置: 主页 > 建站知识 > 软件开发

dsp软件开发与c语言编程-c语言学习路线图c语言经典编程282例

发布时间:2023-05-22 16:11   浏览次数:次   作者:佚名

欢迎FPGA工程师加入官方微信技术群

dsp原理及其c编程开发技术_dsp软件开发与c语言编程_c语言学习路线图c语言经典编程282例

在嵌入式软件的开发过程中,我们常用的语言主要是:汇编语言和C语言。相比较于汇编语言,C语言对我们来说,更贴近我们的一些语言习惯。在DSP的开发过程中,我们主要还是用C语言,其中最最常用的操作就是对于DSP各个寄存器的控制了。

那么如何用C语言对DSP的寄存器进行操作呢?

我们先来说书单片机里面是如何操作的:一般寄存器在单片机头文件中的宏定义都有如下的形式:

#define TIFR  *((volatile unsigned char *)0x58)     /*ATmega16的TIFR寄存器*/

在ATmega16中TIFR寄存器的地址是0x0058,我们要实现:

TIFR = 0x01

这条,就是要把0x58这个地址的内容修改成0x01。而在C语言中,指针就是地址。现在要告诉编译器0x58是地址,就要把0x58强制转换成指针(unsigned char *)0x58。这样(unsigned char *)0x58就表示TIFR在ATmega16 中的地址了,而*((unsigned char *)0x58)表示这个地址的内容。

然后如果想对寄存器TIFR单个的位进行下面的操作,

(1)将寄存器TIFR的第1位置“1”

TIFR |= (1 << 1);

(2) 将寄存器REG的第3位清零

TIFR &= ~(1 << 3);

(3) 将寄存器REG的第3、5位置“1”

TIFR |= (1 << 5) | (1 << 3);

(4) 将寄存器REG的第3、5位清零

TIFR &= ~( (1 << 5) | (1 << 3) );

在单片机里面是使用宏定义的方式来对寄存器进行操作。而在DSP里面,是使用位定义+共同体的方式来定义和操作寄存器。如下:

// ECCTL1控制寄存器的位定义如下:

struct ECCTL1_BITS {          // bits   description
Uint16 CAP1POL:1; // 0 Capture Event 1 Polarity select
Uint16 CTRRST1:1; // 1 Counter Reset on Capture Event 1
Uint16 CAP2POL:1; // 2 Capture Event 2 Polarity select
Uint16 CTRRST2:1; // 3 Counter Reset on Capture Event 2
Uint16 CAP3POL:1; // 4 Capture Event 3 Polarity select
Uint16 CTRRST3:1; // 5 Counter Reset on Capture Event 3
Uint16 CAP4POL:1; // 6 Capture Event 4 Polarity select
Uint16 CTRRST4:1; // 7 Counter Reset on Capture Event 4
Uint16 CAPLDEN:1; // 8 Enable Loading CAP1-4 regs on a Cap Event
Uint16 PRESCALE:5; // 13:9 Event Filter prescale select
Uint16 FREE_SOFT:2; // 15:14 Emulation mode
};


struct ECCTL1_BITS  bit;

在上面的代码中我们用位域的方式表示了TCR寄存器的数据结构。同时声明了一个

struct TCR_BITS类型的变量bit,那么我们就可以通过bit对寄存器每个位进行控制,比如

bit.CTRRST2=0;

此时有一个问题,就是如果我们想对整个寄存器进行整体的控制该如何呢?我们通过定义共同体来实现既可以对寄存器的每个位进行控制,又能对寄存器整体方便的控制。如下:

union ECCTL1_REG {
Uint16 all;
struct ECCTL1_BITS bit;
};

TCR_REG.all=0xxxx;    //对寄存器整体操作
TCR_REG.CTRRST2=0; //对寄存器单个位操作

而在DSP里面,某一个功能是靠一个模块来实现的dsp软件开发与c语言编程,而每一个功能模块包含了许多不同的寄存器,比如28335里面CAP脉冲捕获模块的寄存器就有以下这么多:

c语言学习路线图c语言经典编程282例_dsp原理及其c编程开发技术_dsp软件开发与c语言编程

为了方便统一管理和编程开发方便,TI公司将ECap模块的所有寄存器定义成一个结构体ECAP_REGS,如下:

struct ECAP_REGS {
Uint32 TSCTR; // Time stamp counter
Uint32 CTRPHS; // Counter phase
Uint32 CAP1; // Capture 1
Uint32 CAP2; // Capture 2
Uint32 CAP3; // Capture 3
Uint32 CAP4; // Capture 4
Uint16 rsvd1[8]; // reserved
union ECCTL1_REG ECCTL1; // Capture Control Reg 1
union ECCTL2_REG ECCTL2; // Capture Control Reg 2
union ECEINT_REG ECEINT; // ECAP interrupt enable
union ECFLG_REG ECFLG; // ECAP interrupt flags
union ECFLG_REG ECCLR; // ECAP interrupt clear
union ECEINT_REG ECFRC; // ECAP interrupt force
Uint16 rsvd2[6]; // reserved

};

我们可以看到,在结构体ECAP_REGS中有的成员是 Uint32形式,有的是union形式,其中定义为union形式的成员既可以对寄存器整体操作,又可以对寄存器进行位操作,而定义为Uint16 的成员只能进行位操作。

在定义了ECAP_REGS结构体之后,需要声明ECAP_REGS类型的变量,而28335有6路的ECap,所以声明如下:

extern volatile struct ECAP_REGS ECap1Regs;
extern volatile struct ECAP_REGS ECap2Regs;
extern volatile struct ECAP_REGS ECap3Regs;
extern volatile struct ECAP_REGS ECap4Regs;
extern volatile struct ECAP_REGS ECap5Regs;
extern volatile struct ECAP_REGS ECap6Regs;

其中extern表示声明的是一个全局变量,关键字volatile代表寄存器的值可以被外部代码任意改变,比如被中断改变。

volatile 在 DSP 中的理解:该单词的意思是可变的,易变的。在 DSP 中一些寄存器的值的变化有两种情况:

(1)硬件上导致的变化,例如中断、ADC 等

(2)软件上的变化,例如对某个变量赋值等。

当加入了关键字 volatile,对软件来说dsp软件开发与c语言编程,硬件上变化的值是不可预知的,提示编译器每次读取该变量时,都要直接读取该变量地址中的寄存器,保证了数据的正确性。

以上我们回顾一下:经过位定义——共同体——结构体的过程就是TI公司提供给我们的DSP2833x_ECap.h里面的内容。

而28335的寄存器结构是固定不变的,所以这个头文件我们在项目的开发中就可以直接拿来用了,添加到include中即可。

此外,大家也不必去死记各种各样的寄存器,因为CCS软件有“感应”功能。在我们加载了头文件之后,输入寄存器名字之后,输入“.”就会弹出可选的下拉列表来选择你需要的寄存器。

ECap1Regs.ECCTL1_REG.bit.CAP2POL=0xxxxx;

上面一行代码从右至左依次代表:

功能模块结构体——某一个寄存器——寄存器的某一位;

这样我们就可以在自己的.c源文件中对各种各样的寄存器进行配置和操作,来实现自己的开发目的。

dsp原理及其c编程开发技术_c语言学习路线图c语言经典编程282例_dsp软件开发与c语言编程