79-使用TFT彩屏8位数据口接R-2R电阻做DAC通过DMA输出波形,AI8051U实验箱演示程序
79-使用TFT彩屏8位数据口接R-2R电阻做DAC通过DMA输出波形,AI8051U实验箱演示程序主程序main.C代码如下(汇编版本在附件中):
/*---------------------------------------------------------------------*/
/* --- Web: www.STCAI.com ---------------------------------------------*/
/* --- BBS: www.STCAIMCU.com-----------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了STC的资料及程序 */
/*---------------------------------------------------------------------*/
/*************功能说明 **************
本例程基于AI8051U为主控芯片的实验箱V1.2版本进行编写测试。
使用Keil C51编译器,为了达到比较高的效率,一般建议选择"Small"模式。
当编译器出现 "error C249: 'DATA': SEGMENT TOO LARGE" 错误时,则需要手动将部分比较大的数组通过"xdata" 强制分配到 XDATA 区域(例如: char xdata buffer ;)
使用TFT彩屏接口+DMA将正弦波数据输出P2口接R-2R做DAC输出正弦波(或任意波形)。
本例为32点正弦波,此法将极大程序减少对CPU的占用,中断频率为输出波形的频率,比如输出2000Hz的正弦波,如果用传统的中断重装方式,将需要64KHz(15.625us)的中断,严重拖累CPU。
而使用本方法,中断率为2000Hz,并且中断仅仅是重启DMA。
注意:重启DMA需要大约1us的时间,会附加到输出波形中,引起失真,当波形小于5000Hz时,影响可以忽略,大于10KHz时,影响开始能检测到。
******************************************/
#define MAIN_Fosc 40000000UL
#include "../comm/AI8051U.h"
#include <intrins.h>
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
#define Pin0 0x01 //IO引脚 Px.0
#define Pin1 0x02 //IO引脚 Px.1
#define Pin2 0x04 //IO引脚 Px.2
#define Pin3 0x08 //IO引脚 Px.3
#define Pin4 0x10 //IO引脚 Px.4
#define Pin5 0x20 //IO引脚 Px.5
#define Pin6 0x40 //IO引脚 Px.6
#define Pin7 0x80 //IO引脚 Px.7
#define PinAll 0xFF //IO所有引脚
#define P1n_standard(bitn) P1M1 &= ~(bitn), P1M0 &= ~(bitn)
#define P1n_push_pull(bitn) P1M1 &= ~(bitn), P1M0 |=(bitn)
#define P1n_pure_input(bitn) P1M1 |=(bitn), P1M0 &= ~(bitn)
#define P1n_open_drain(bitn) P1M1 |=(bitn), P1M0 |=(bitn)
#define P2n_standard(bitn) P2M1 &= ~(bitn), P2M0 &= ~(bitn)
#define P2n_push_pull(bitn) P2M1 &= ~(bitn), P2M0 |=(bitn)
#define P2n_pure_input(bitn) P2M1 |=(bitn), P2M0 &= ~(bitn)
#define P2n_open_drain(bitn) P2M1 |=(bitn), P2M0 |=(bitn)
#define P3n_standard(bitn) P3M1 &= ~(bitn), P3M0 &= ~(bitn)
#define P3n_push_pull(bitn) P3M1 &= ~(bitn), P3M0 |=(bitn)
#define P3n_pure_input(bitn) P3M1 |=(bitn), P3M0 &= ~(bitn)
#define P3n_open_drain(bitn) P3M1 |=(bitn), P3M0 |=(bitn)
#define P4n_standard(bitn) P4M1 &= ~(bitn), P4M0 &= ~(bitn)
#define P4n_push_pull(bitn) P4M1 &= ~(bitn), P4M0 |=(bitn)
#define P4n_pure_input(bitn) P4M1 |=(bitn), P4M0 &= ~(bitn)
#define P4n_open_drain(bitn) P4M1 |=(bitn), P4M0 |=(bitn)
//=============================================================================================================
#define PullUpEnable(port, pu) port |=(pu) /* 允许端口内部上拉电阻 PxPU, 要设置的端口对应位为1 */
#define PullUpDisable(port, pu) port &= ~(pu) /* 禁止端口内部上拉电阻(默认) PxPU, 要设置的端口对应位为1 */
#define PullDownEnable(port, pu) port |=(pu) /* 允许端口内部下拉电阻 PxPD, 要设置的端口对应位为1 */
#define PullDownDisable(port, pu) port &= ~(pu) /* 禁止端口内部下拉电阻(默认) PxPD, 要设置的端口对应位为1 */
#define SchmitEnable(port, smt) port &= ~(smt) /* 允许端口施密特触发功能(默认) PxNCS, 要设置的端口对应位为1 */
#define SchmitDisable(port, smt) port |=(smt) /* 允许端口施密特触发功能 PxNCS, 要设置的端口对应位为1 */
#define SlewRateNormal(port, sr) port |=(sr) /* 端口输出设置为普通速度(默认) PxSR, 要设置的端口对应位为1 */
#define SlewRateHigh(port, sr) port &= ~(sr) /* 端口输出设置为高速模式 PxSR, 要设置的端口对应位为1 */
#define CurrentNormal(port, cu) port |=(cu) /* 端口输出电流为普通模式(默认) PxDR, 要设置的端口对应位为1 */
#define CurrentHigt(port, cu) port &= ~(cu) /* 端口输出电流为大电流模式 PxDR, 要设置的端口对应位为1 */
#define InputEnable(port, ie) port |=(ie) /* 允许端口数字输入(默认) PxIE, 要设置的端口对应位为1 */
#define InputDisable(port, ie) port &= ~(ie) /* 禁止端口数字输入 PxIE, 要设置的端口对应位为1 */
#define BypassEnable(port, bp) port &= ~(bp) /* 允许外设自动控制端口 PxBP, 要设置的端口对应位为1 */
#define BypassDisable(port, bp) port |=(bp) /* 禁止外设自动控制端口(默认) PxBP, 要设置的端口对应位为1 */
//=============================================================================================================
/****************************** 用户定义宏 ***********************************/
sbit LCD_RS = P4^5;//悬空不用
sbit LCD_RW = P3^6;//悬空不用
sbit LCD_E= P3^7; //悬空不用
sbit LCD_RESET = P4^7; //悬空
#define LCD_Data P2
/*****************************************************************************/
/*************本地常量声明 **************/
/*************本地变量声明 **************/
u8 xdata T_SINE={
128,
153,
177,
199,
218,
234,
245,
253,
255,
253,
245,
234,
218,
199,
177,
153,
128,
103,
79,
57,
38,
22,
11,
3,
1,
3,
11,
22,
38,
57,
79,
103,
};
/*************本地函数声明 **************/
void LCM_Config(void);
void DMA_Config(u8 xdata *wav);
/********************* 主函数 *************************/
void main(void)
{
EAXSFR(); //扩展寄存器(XFR)访问使能
WTST= 0; //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
CKCON = 0; //提高访问XRAM速度
P0M1 = 0x00; P0M0 = 0x00; //设置为准双向口
P1M1 = 0x00; P1M0 = 0x00; //设置为准双向口
P2M1 = 0x00; P2M0 = 0x00; //设置为准双向口
P3M1 = 0x00; P3M0 = 0x00; //设置为准双向口
P4M1 = 0x00; P4M0 = 0x00; //设置为准双向口
P5M1 = 0x00; P5M0 = 0x00; //设置为准双向口
P6M1 = 0x00; P6M0 = 0x00; //设置为准双向口
P7M1 = 0x00; P7M0 = 0x00; //设置为准双向口
LCM_Config();
EA = 1;
DMA_Config(T_SINE);
P40 = 0; //接R-2R的地(这样接方便,但接GND更好).
P2n_pure_input(0xff); // P2要设置为高阻,否则IO输出电平会干扰数据,即LCM不控制IO时回复IO的输出。
BypassEnable(P2BP, 0xff); // 允许外设自动控制端口 PxBP, 要设置的端口对应位为1, 外设自动控制P0口, 使用外部总线时,如果P2BP=0x00则P2由硬件控制,P2的模式设置不影响总线,如果P2BP=0xff则P2设置会影响总线访问。
BypassEnable(P3BP, 0xc0); // 允许外设自动控制端口 PxBP, 要设置的端口对应位为1, 外设自动控制P0口, 使用外部总线时,如果P2BP=0x00则P2由硬件控制,P2的模式设置不影响总线,如果P2BP=0xff则P2设置会影响总线访问。
BypassEnable(P4BP, 0xa0); // 允许外设自动控制端口 PxBP, 要设置的端口对应位为1, 外设自动控制P0口, 使用外部总线时,如果P2BP=0x00则P2由硬件控制,P2的模式设置不影响总线,如果P2BP=0xff则P2设置会影响总线访问。
while(1)
{
NOP(10);
}
}
//========================================================================
// 函数: void LCM_Config(void)
// 描述: LCM配置函数。 LCM DMA发送周期:LCMIFPSCR=0(1分频)时,=(1+E+K+S)T+3Ts,LCMIFPSCR!=0(>=2分频)时, =(1+E+K+S)T+4Ts, T为LCMIF时钟周期, Ts为系统时钟周期, E为数据建立时间,K为数据保持时间,S为DMA间隔时间。
// 参数: none.
// 返回: none.
// 版本: V1.0, 2024-8-17
// 备注:
//========================================================================
//LCMIFCFG(7EFE50H) TFT彩屏接口配置寄存器
#define LCMIFIE (0<<7) //TFT彩屏接口中断使能控制位(bit7), 1->允许中断,0->禁止
#define LCMIFIP (0<<4) //TFT彩屏接口中断优先级控制位(bit5~bit4), (最低)0~3(最高).
#define LCMIFDPS (0<<2) //TFT彩屏接口数据脚选择位(bit3~bit2), D18_D8=0: 0或2->8位数据在P2, D18_D8=1: 0: P2-高字节, P0低字节, 2: P2-高字节,低字节P0 P4.7 P4.6 P4.3 P4.1.
#define LCM_D16_D8 (0<<1) //TFT彩屏接口数据宽度控制位(bit1), 0: 8位数据,1:16位数据
#define LCM_M68_I80 1 //TFT彩屏接口数据模式选择位(bit0), 0: I8080模式,1:M6800模式
//LCMIFCFG2(7EFE51H) TFT彩屏接口配置寄存器2
#define LCMIFCPS (1<<5) //TFT彩屏接口控制脚选择位(bit6~bit5), RS RD(E) WR(RW), 0->P4.5 P4.4 P4.2,1->P4.5 P3.7 P3.6, 2->P4.0 P4.4 P4.2, 3->P4.0 P3.7 P3.6
#define LCMSETUPT (7<<2) //TFT彩屏接口数据建立时间控制位(bit4~bit2), 0~7, 对应1~8个LCMIF时钟, 即E信号高电平时间.
#define LCMHOLDT 3 //TFT彩屏接口数据保持时间控制位(bit1~bit0), 0~3, 对应1~4个LCMIF时钟
//LCMIFCR(7EFE52H) TFT彩屏接口控制寄存器
#define ENLCMIF (1<<7) //TFT彩屏接口使能控制位(bit7), 1->允许TFT彩屏接口功能, 0->禁止
#define LCM_WRCMD 4 //TFT彩屏接口触发命令(bit2~bit0), 4->写命令
#define LCM_WRDAT 5 //TFT彩屏接口触发命令(bit2~bit0), 5->写数据
#define LCM_RDCMD 6 //TFT彩屏接口触发命令(bit2~bit0), 6->读命令/状态
#define LCM_RDDAT 7 //TFT彩屏接口触发命令(bit2~bit0), 7->读数据
void LCM_Config(void)
{
LCMIFCFG= LCMIFIE| LCMIFIP | LCMIFDPS | LCM_D16_D8 | LCM_M68_I80;
LCMIFCFG2 = LCMIFCPS | LCMSETUPT | LCMHOLDT; //RS:P45,E:P37,RW:P36; Setup Time,HOLD Time
LCMIFSTA= 0x00; //TFT彩屏接口中断请求标志,软件清0
LCMIFPSCR = 1-1; //TFT彩屏接口时钟预分频0~255, LCMIF时钟频率 = SYSclk/(LCMIFPSCR+1), LCD12864速度慢,最快250KHz
LCMIFCR = ENLCMIF;
}
//========================================================================
// 函数: void DMA_Config(u8 xdata *wav)
// 描述: LCM DMA配置函数。
// 参数: *wav: 数据首地址.
// 返回: none.
// 版本: V1.0, 2024-8-17
// 备注:
//========================================================================
//DMA_LCM_CR (7EfA71H) LCM_DMA控制寄存器
#define DMA_ENLCM (1<<7) // LCM DMA功能使能控制位, bit7, 0:禁止LCM DMA功能,1:允许LCM DMA功能。
#define LCM_TRIGWC (1<<6) // LCM DMA触发写命令,bit6, 0:写0无效, 1:写1开始LCM DMA开始写命令。
#define LCM_TRIGWD (1<<5) // LCM DMA触发写数据,bit5, 0:写0无效, 1:写1开始LCM DMA开始写数据。
#define LCM_TRIGRC (1<<4) // LCM DMA触发读命令,bit4, 0:写0无效, 1:写1开始LCM DMA开始读命令。
#define LCM_TRIGRD (1<<3) // LCM DMA触发读数据,bit3, 0:写0无效, 1:写1开始LCM DMA开始读数据。
#define LCM_CLRFIFO 0 // 清除LCM DMA接收FIFO控制位,bit0, 0:写0无效,1:写1复位FIFO指针。
//DMA_LCM_CFG (7EfA70H) LCM_DMA配置寄存器
#define DMA_LCMIE (1<<7) // LCM DMA中断使能控制位,bit7, 0:禁止SPI DMA中断, 1:允许中断。
#define DMA_LCMIP (0<<2) // LCM DMA中断优先级控制位,bit3~bit2, (最低)0~3(最高).
#define DMA_LCMPTY 0 // LCM DMA数据总线访问优先级控制位,bit1~bit0, (最低)0~3(最高).
//DMA_LCM_STA(7EfA72) LCM_DMA状态寄存器
#define LCM_TXOVW (1<<1) // LCM DMA数据覆盖标志位,bit1, 软件清0.
#define DMA_LCMIF 1 // LCM DMA中断请求标志位,bit0, 软件清0.
#define LCM_ITVH 1233 //输出1000Hz正弦波@40MHz, 32点正弦波表,LCM耗时17T,则间隔时间=40000/32-17=1233
// #define LCM_ITVH 608 //输出2000Hz正弦波@40MHz, 32点正弦波表,LCM耗时17T,则间隔时间=40000/64-17=608
// #define LCM_ITVH 233 //输出5000Hz正弦波@40MHz, 32点正弦波表,LCM耗时17T,则间隔时间=40000/160-17=233
// #define LCM_ITVH 108 //输出 10KHz正弦波@40MHz, 32点正弦波表,LCM耗时17T,则间隔时间=40000/320-17=108
void DMA_Config(u8 xdata *wav)
{
u16 LCM_TxAddr;
LCM_TxAddr = (u16)wav; //要发送数据的首地址
DMA_LCM_TXAH = (u8)(LCM_TxAddr >> 8); //LCM DMA发送数据首地址
DMA_LCM_TXAL = (u8)LCM_TxAddr;
DMA_LCM_AMTH = 0; //设置传输总字节数(高8位), 设置传输总字节数 = N+1
DMA_LCM_AMT= 32-1; //设置传输总字节数(低8位).
DMA_LCM_STA= 0x00;
DMA_LCM_CFG= DMA_LCMIE | DMA_LCMIP | DMA_LCMPTY;;
DMA_LCM_ITVH = (u8)((LCM_ITVH-1)/256); //设置传输间隔时间(高8位),对应N+1个LCMIF时钟(1~65536个LCMIF时钟)
DMA_LCM_ITVL = (u8)((LCM_ITVH-1)%256); //设置传输间隔时间(低8位)
DMA_LCM_CR = DMA_ENLCM | LCM_TRIGWD; //启动LCM DMA发送数据
}
//========================================================================
// 函数: void LCMIF_DMA_ISR(interrupt USER_VECTOR//DMA_LCM_VECTORVECTOR
// 描述: LCM DMA中断函数。
// 参数: none.
// 返回: none.
// 版本: V1.0, 2024-8-17
// 备注:
//========================================================================
void LCMIF_DMA_ISR(void) interrupt USER_VECTOR//DMA_LCM_VECTOR
{
DMA_LCM_CR = DMA_ENLCM | LCM_TRIGWD; //启动DAM
DMA_LCM_STA = 0;
}
页:
[1]