微机原理(DSP)笔记
课程笔记
时钟与系统控制
从属 | 名称 | 描述 | 使用 |
---|---|---|---|
外部 | OSCCLK | 外部晶振信号 | |
时钟控制 | PLLCR | 提供倍数于参考信号的系统时钟 | \(\text{SYSCLK}=\frac{f\cdot\text{PLLCR}}2\) |
PCLKCR | 外设时钟信号 | ||
HISPCP | 高速时钟信号 | ||
LOSPCP | 低速时钟信号 | ||
看门狗 | WDCR | 看门狗时钟寄存器 | 含使能控制、逻辑校验位、频率设置 |
SCSR | 系统控制和状态寄存器 | 含WDINTS(中断状态位)、WDENNIT(中断使能位) | |
低功耗 | LPMCR0 | 低功耗控制寄存器0 | 低二位LPM控制低功耗模式,QUALSTDBY控制频率 |
LPMCR1 | 低功耗控制寄存器1 | 低八位控制STDBY模式的唤醒(全1唤醒) |
GPIO
从属 | 名称 | 描述 | 使用 |
---|---|---|---|
控制寄存器 | GPxMUX | 功能选择控制寄存器 | ‘0’ - I/O;‘1’ - 外设 |
GPxDIR | 方向控制寄存器 | ‘0’ - Input;‘1’ - Output | |
GPxQUAL | 输入限定控制 | 使输入在n个采样相同时才变化 | |
数据寄存器 | GPxDAT | 数据寄存器 | 16位 |
CPU定时器
从属 | 名称 | 描述 | 使用 |
---|---|---|---|
减法计数 | TIMER0TIM | 计数器寄存器 | 32位减法计数器,减到0产生中断(控制寄存器) |
TIMER0TIMH | 与上面的合起来 | ||
赋值(高位) | TIMER0PRD | 周期寄存器 | 定义为long int* ,可以直接实现两个一起赋值,最大4G |
TIMER0PRDH | 合起来的话,在上面那个地方赋值 | ||
控制 | TIMER0PCR | 控制寄存器 | 15位 - 中断标志位,计数器减到0置1,否则为0,写入1清零 5位 - 定时器重装,写1时重装PRD和TDDR(TPR)的值 |
赋值(低位) | TIMER0TPR | 预定标寄存器 | 必须分两块写入数据,每块16位最大256 bit |
TIMER0TPRH | 跟上面那个都定义为unsigned int* | ||
控制 | TIMER0TCR | 定时器控制寄存器 | 第15位 - 中断标志位。定时器到0时置1,写入1清零 |
因此:
\[ T=\frac{\text{TDDRH:TDDR}+1}{\text{SYSCLKOUT}(Hz)}\cdot(\text{PRDH:PRD}+1) \]
中断
从属 | 名称 | 描述 | 使用 |
---|---|---|---|
CPU中断 | IER | 中断使能寄存器(16位) | ‘0’ - 禁止;‘1’ - 使能 |
IFR | 中断标志寄存器(16位) | ‘0’ - 清零;‘1’ - 中断 | |
INTM | 全局中断使能寄存器 | ‘1’ - 全局使能 | |
PIE中断 | PIRIER | PIE中断使能寄存器(12×8) | 同上 |
PIEIFR | PIE中断标志寄存器(12×8) | 同上 | |
PIEACK | PIE中断应答寄存器 | 不确定几位,清0申请中断,置1为等待状态 | |
PIECTRL | PIE控制寄存器 | ENPIE,位0,置1表示向量取自PIE向量表 |
存储器与寄存器
存储器与CMD
CMD:记录下如何分配存储空间内容的文件
CMD的工作分为两步:
- MEMORY:指示定义存储空间
- SECTIONS:分配存储空间
1 | /* SRAM.CMD */ |
在C语音中已经预先定义好了很多“段”,我们可以直接拿来用,或者我们可以自己新建或定义“段”,用于存放我们所需要的变量。方法如下:
1 | /* 写法 */ |
寄存器
位域与结构:为了解决(1)不能对位变量的独立操作;(2)每一位都要写出具体数字;的问题。下面简述我们的解决方案
(一)定义一个位结构(位域)——> 联合结构(共同体)
1 | /* 以下文件应该放在.h文件(Head)下 */ |
演示一下调用方法:
1 | union GPFDAT_REG GPFDAT; |
(二)定义一个包含一组联合的结构(结构体文件)
说来复杂,其实也不难,就是把刚刚我们的一堆共同体union丢到一起,就是结构体文件了。一个结构体文件相当于一个班。
1 | /* 以下文件应该放在.h文件(Head)下 */ |
(三)申明结构体变量实体,并指定其与section的关系(即分配空间)
前半句话,就是上面(二)代码块中的最后一行,合并在一起写了
后半句话,参考CMD中的progma代码段,一般常用的都定义好了
1 | /* 以下文件应该放在.c文件下 */ |
(四)在链接命令文件CMD中建立连接
参考CMD中的第一个代码块
1 | MEMORY{ |
(五)成功调用
变量成为一个结构的成员,同时又有了自己的地址
1 | GpioDataRegs.GPFDAT.bit.GPIO11 = 1; |
串行外设接口SPI
从属 | 名称 | 描述 | 使用 |
---|---|---|---|
配置 | SPICCR | SPI配置控制寄存器 | 第6位控制信号极性(上升/下降沿) 0-3位控制单个字符读取数量 |
控制 | SPICTL | SPI工作控制寄存器 | 第2位网络模式控制(‘0’ - 从机;‘1’ - 主机) 第1位主从机发送使能TALK;第0位中断使能 |
状态 | SPISTS | SPI状态寄存器 | 第7位接收器溢出标志 第6位只读中断标志INT FLAG(完成数据发送/接收) 第5位发送缓冲器已满标志位FULL |
时钟 | SPIBRR | SPI波特率寄存器 | 第0-6位控制波特率(\(Rate=\frac{LSPCLK}{SPIBRR+1}\)) |
数据 | SPIRXBUF | SPI串行接收缓存寄存器 | 接收后INT FLAG置1 |
SPITXBUF | SPI串行发送缓存寄存器 | 发送后TX BUF FULL被清除 | |
SPIDAT | SPI串行数据寄存器 | 略 |
事件管理器EV
- 以EVA的Timer1为例
从属 | 名称 | 描述 | 使用 |
---|---|---|---|
控制 | GPTCONA | 全局控制寄存器A | .T1PIN:比较输出极性,01低,10高 .T1CMPOE:比较输出使能(1有效) .TCMPOE:全局比较输出使能(1有效) |
T1CON | 定时器1控制寄存器 | .TECMPR:定时器比较使能(1有效) .TCLKS10:时钟源(00内部时钟) .TENABLE:定时器使能(1有效) .TPS:输入时钟预定标因子(分频:HSPCLK/2^n) .TMODE10:计数模式(01连续增减,10连续增) | |
计数 | T1CNT | 定时器1计数寄存器 | 略 |
T1PR | 定时器1周期寄存器 | 略 | |
T1CMPR | 定时器1比较寄存器 | 略 | |
死区 | DBTCONA | 死区定时器控制寄存器 | .DBTPS:死区定时器预定标因子(分频:T1时钟/2^n) .EDBT1:死区定时器1使能(1有效) .DBT:死区周期 |
PWM波 | CMPR1 | 比较寄存器1 | 略 |
数模转换器ADC
- ADC的时钟分频:
- 准备:PCLKCR使能
- 外部晶振信号30MHz——PLLCR=0xA——SYSCLKOUT=150MHz
- HISPCP=001(例)——HSPCLK=150/2MHz=75MHz
- ADCTRL3.ADCCLKPS分频(2n)倍(n=0时不起作用)
- ADCTRL1.CPS分频(m+1)倍
从属 | 名称 | 描述 | 使用 |
---|---|---|---|
控制 | ADCTRL1 | ADC控制寄存器1 | .CPS:内核时钟预定标,用于分频 .CONT RUN:连续运行or启停模式(一般选0启停) .SEQ CASC:SEQ级联or双序列 |
ADCTRL2 | ADC控制寄存器2 | .RST1:复位序列发生器 .SOC SEQ1:序列发生器1启动触发,主动写入/中断自动调用 .INT ENA SEQ1:中断使能 .INT MOD SEQ1:中断方式(每个/隔一个) .EVA SOC SEQ1:事件管理器EVA允许触发使能 其余有关SEQ2的略,类似 | |
ADCTRL3 | ADC控制寄存器3 | .ADCBGRFDN:上电,一般写1,需要长延时 .ADCPWDN:上电,一般写1,需要长延时 .ADCCLKPS:时钟分频 .SMODE SEL:采样方式:顺序or并发 | |
序列 | MAXCONV | 最大转换通道寄存器 | 进行(n+1)次转换 |
ADCCHSELSEQ1-4 | 输入通道选择序列控制寄存器 | 见书p254,一个CHSELSEQ有4个CONV,一个CONV寄存一个输入 | |
状态 | ADCASEQSR | 自动序列状态寄存器 | 看不懂 |
ADCST | ADC状态和标志寄存器 | .INT SEQx CLR:中断清除位,写1清除 .SEQx BSY:忙状态位,0表示空闲,只读 .INT SEQx:中断标志位,1表示有中断,只读 |
C语言代码
基本代码定义与框架
引脚定义实例
1 |
控制时钟PLL初始化
1 | void InitPLL(){ |
看门狗初始化
1 | void DisableDog(){ |
外设时钟初始化
1 | void InitPeripheralClock(){ |
总初始化 InitSysCtrl
写法1
1 | void InitSysCtrl(){ |
写法2
1 | void InitSysCtrl(){ |
GPIO初始化 InitGpio
1 | void InitGpioF(){ |
CPU定时器初始化 InitCPUtimer
1 |
|
时钟延时函数
1 | // 已经定义过InitCPUtimer |
PIE中断初始化 InitPIE
1 | // 假设仅使用INT1.7,仅允许该中断通过 |
中断向量的申请
1 | // 1. 申明 |
CPU中断初始化
1 | void InitCPU(void){ |
SPI初始化
1 | void InitSpi(void){ |
SPI数据发送
1 | void SpiSent(int k){ |
点红灯函数
1 | int redled = 0xffff; |
八段数码管循环
1 | void Display(void){ |
键盘的读取
1 | int Keyin = 0xffff; |
等待键盘输入
1 | void WaitKeyin(void){ |
键号判别、功能转移
1 | void main(void){ |
通用定时器编程初始化
1 | void EVA_Timer1(){ |
设置PWM波周期波形
- 准备:PCLKCR使能EVA时钟
- 晶振30MHz——PLLCR=10——SYSCLK=150MHz
- HISPCP=001(例)——HSPCLK=150/2MHz=75MHz(见书p134)
- T1CON.TPS10=n——T1CLK:HSPCLK/2^ n=75/2^n MHz
- T1PR = T1CLK / 要求的时钟频率 - 1
- T1PWM,T2PWM不带死区
- PWM1-6带死区,12、34、56互补
1 | void InitEVA(void){ |
ADC上电
1 | void AdcPower(void){ |
ADC初始化
1 | void InitAdc(void){ |
ADC调用示例
1 | void AdcFunction(void){ |
键盘与红灯的冲突解决方案
原因是两者都会调用GPB和GPE,且键盘需要一直进行监视(Keyscan()
),不能把GPB放出来。
- 选择将
Keyscan()
这个函数放到CPUTimer中,而不是在main的死循环里面调用。 - 将
Keyscan()
函数中的输出值放到全局变量中,并尽可能减小其时间,即删去防抖动的延时、减小反应时间延时。 WaitKeyin()
函数不再被允许调用Keyscan()
,而是直接读取数值- 在
Keyscan()
中的开头和结尾都要加上对GPB的控制
1 | int Keyin = 0xffff; |
实例
实例1 点灯
- 点亮六盏灯,利用GPIOF的8-13位输出。(高电平灭灯)
1 |
|
实例2 中断编程
- 利用TIMER0中断,使GPIOF8闪烁,周期为3s,亮1s。
1 | typedef interrupt void(*PINT)(void); |
实例3 绿灯闪烁+点红灯
- GPIOE
输入 | 效果 |
---|---|
2 | 选择寄存器1,即GPBDAT与左边八盏红灯建立联系 |
3 | 选择寄存器2,即GPBDAT与右边八盏红灯建立联系 |
7 | 产生一个下降沿,使寄存器(GPBDAT)发送数据 |
- GPIOB
输入数据的前八位控制红灯(初始化GPBDIR为0xFF00)
如GPBDAT = 0xfeff
,且GPEDAT = 2
,则左边第一盏红灯亮。(DAT最低位对应第一盏灯)
1 |
|
实例4 键盘响应+时钟+AD转换
1 |
|
实例5 跑马灯——正弦亮度变化
1 |
|
此文章版权归Paradox所有,如有转载,请注明来自原作者
评论