/*------------------------------------------------ 波特率自适应技术在DSP5402上的应用之C++接收程序 菜农 HotPower@126.com 2005.6.30 23:30 于西安大雁塔村队部 菜地: http://hotpower.21ic.org ------------------------------------------------*/ #include <cstdio> //C语言可以用stdio.h #include <cstring>//C语言可以用string.h #include "C5402DEF.h"//DSP菜鸟HotPower创建 #include "class.h" #define ccsdebug 1//1--IO模拟SPI; 0--硬件McBSP模块 extern "C" interrupt void Timer0Isr();//注意加extern "C" extern "C" interrupt void Timer1Isr(); extern "C" interrupt void Eint0Isr(); extern "C" interrupt void Eint1Isr(); extern "C" interrupt void Eint2Isr(); extern "C" interrupt void Eint3Isr(); SystemObj::SystemObj(void) { Disable();//关中断 SREG->IMR = 0x0000;// SREG->IFR = 0xffff;//清除 //设置0x0080为中断向量表首址,在第2个128页内。 SREG->PMST = (0x01 << PMST_IPTR) | (1 << PMST_MP_MC) | (1 << PMST_OVLY); // SREG->PMST |= (1 << PMST_DROM);//数据可const. /*--------------------------------------------------------------------------- 若:设置0x0100为中断向量表首址,在第3个128页内。 则:*.cmd文件应该改为: PAGE 0: VECS: origin=0x0100, length=0x66 则: SREG->PMST = (0x02 << PMST_IPTR) | (1 << PMST_MP_MC) | (1 << PMST_OVLY); ----------------------------------------------------------------------------*/ SystemInit();//系统初始化 } void SystemObj::SystemInit(void) { PllInit();//PLL初始化 TIMER0Init(); TIMER1Init(); EintInit(); /*-------------------------------------------------------- 注意以下2个变量的作用域的不同 --------------------------------------------------------*/ if (::SystemRamTest != 0x55aa) {//全局变量SystemRamTest ::SystemRamTest = 0x55aa;//改写全局变量 } if (SystemRamTest != 0x55aa) {//类成员变量SystemRamTest SystemRamTest = 0x55aa;//改写类成员变量 } ::IOXF = 0; } void SystemObj::PllInit(void) { volatile unsigned int start; SREG->SWWSR = 0x2000; do { SREG->CLKMD = 0; __nop(); } while(SREG->CLKMD & (1 << CLKMD_PLLSTATUS)); // SREG->CLKMD = (0 << CLKMD_PLLMUL) | (30 << CLKMD_PLLCOUNT) | (1 << CLKMD_PLLONOFF) | (1 << CLKMD_PLLNDIV) | (1 << CLKMD_PLLSTATUS);//10M SREG->CLKMD = (9 << CLKMD_PLLMUL) | (30 << CLKMD_PLLCOUNT) | (1 << CLKMD_PLLONOFF) | (1 << CLKMD_PLLNDIV) | (1 << CLKMD_PLLSTATUS);//100M // SREG->CLKMD = (14 << CLKMD_PLLMUL) | (30 << CLKMD_PLLCOUNT) | (1 << CLKMD_PLLONOFF) | (1 << CLKMD_PLLNDIV) | (1 << CLKMD_PLLSTATUS);//150M for (start = 0; start < 10000; start ++);//等待外设上电复位正常结束 } void SystemObj::TIMER0Init(void) { TIMER0->TCR = (1 << TCR_TSS);//关闭定时器0 TIMER0->PRD = 60000;//设置定时周期 TIMER0->TIM = 60000;//设置定时计数器 TIMER0->TCR &= ~(1 << TCR_TSS);//启动定时器0 SREG->IMR |= (1 << IMR_TINT0);//允许TINT0中断 } void SystemObj::TIMER1Init(void) { TIMER1->TCR = (1 << TCR_TSS);//关闭定时器1 TIMER1->PRD = 0xffff;//设置定时周期 TIMER1->TIM = 0xffff;//设置定时计数器 // TIMER1->TCR &= ~(1 << TCR_TSS);//启动定时器1 // SREG->IMR |= (1 << IMR_TINT1);//允许TINT1中断 } void SystemObj::EintInit(void) { SREG->IMR |= (1 << IMR_INT0);//允许INT0中断 SREG->IMR |= (1 << IMR_INT1);//允许INT1中断 SREG->IMR |= (1 << IMR_INT2);//允许INT2中断 SREG->IMR |= (1 << IMR_INT3);//允许INT3中断 } LcdObj::LcdObj(void) { LcdInit(); } void LcdObj::LcdSpiSetup(void) { #if (ccsdebug == 0) /*----------------------------------------------------------- 硬件McBSP模块配置为SPI接口 实验目的: 演练硬件McBSP模块配置为SPI接口的应用。 ------------------------------------------------------------*/ McBSP1->SPSA = SPCR1; McBSP1->SPSD = 0; // McBSP1->SPSD &= ~(1 << SPCR1_RRST);//禁止串口接收 _delay_loop_(1);//延时等待 McBSP1->SPSA = SPCR2; McBSP1->SPSD = 0; // McBSP1->SPSD &= ~(1 << SPCR2_XRST);//禁止串口发送 _delay_loop_(1);//延时等待 McBSP1->SPSA = SPCR1; McBSP1->SPSD = (0x02 << SPCR1_CLKSTP);//CLKSTP=10b _delay_loop_(1);//延时等待 McBSP1->SPSA = PCR; McBSP1->SPSD = (1 << PCR_FSXM) //设置FSX引脚为输出,控制LCD12864的片选信号SS | (0 << PCR_FSXP) //FSX引脚平时输出低电平(LCD12864的片选信号SS无效) | (1 << PCR_CLKXM) //设置CLKX引脚为输出 | (1 << PCR_CLKXP);//CLKXP引脚平时输出高电平 _delay_loop_(1);//延时等待 McBSP1->SPSA = SRGR1; McBSP1->SPSD = (0x07 << SRGR1_FWID) //0x00~0x07~0xff | (0x80 << SRGR1_CLKGDV);//速率0x80 _delay_loop_(1);//延时等待 McBSP1->SPSA = SRGR2; McBSP1->SPSD = (1 << SRGR2_CLKSM);// _delay_loop_(1);//延时等待 McBSP1->SPSA = RCR1; McBSP1->SPSD = (0x00 << RCR1_RFRLEN1);//8BIT _delay_loop_(1);//延时等待 McBSP1->SPSA = XCR1;//延时等待 McBSP1->SPSD = (0x00 << XCR1_RFRLEN1);//8BIT _delay_loop_(1);//延时等待 McBSP1->SPSA = RCR2; McBSP1->SPSD = (0x02 << RCR2_RDATDLY);//0x01 _delay_loop_(1);//延时等待 McBSP1->SPSA = XCR2; McBSP1->SPSD = (0x02 << XCR2_RDATDLY);//0x01 _delay_loop_(1);//延时等待 McBSP1->SPSA = SPCR2; McBSP1->SPSD |= (1 << SPCR2_GRST) | (1 << SPCR2_XRST) | (1 << SPCR2_FRST); _delay_loop_(1);//延时等待 #else /*----------------------------------------------------------- 硬件McBSP模块配置为普通IO软件模拟SPI时序 实验目的: 演练硬件McBSP模块配置为普通IO的应用.以备IO紧缺时急用。 ------------------------------------------------------------*/ McBSP1->SPSA = SPCR1; McBSP1->SPSD = 0; McBSP1->SPSD &= ~(1 << SPCR1_RRST);//禁止串口接收 McBSP1->SPSA = SPCR2; McBSP1->SPSD = 0; McBSP1->SPSD &= ~(1 << SPCR2_XRST);//禁止串口发送 McBSP1->SPSA = PCR; McBSP1->SPSD = (1 << PCR_XIOEN) | (1 << PCR_RIOEN);//设置收发为IO接口,DX输出,DR,CLKS输入 McBSP1->SPSD |= (1 << PCR_FSXM) | (1 << PCR_CLKXM);//设置FSX,CLKX可做IO输出 McBSP1->SPSD |= (1 << PCR_FSRM) | (1 << PCR_CLKRM);//设置FSR,CLKR可做IO输出 McBSP1->SPSD &= ~(1 << PCR_FSXP);//FSX信号=0 McBSP1->SPSD |= (1 << PCR_CLKXP);//CLKX信号=1 McBSP1->SPSD |= (1 << PCR_DX_STAT);//DX信号=1 #endif } void LcdObj::LcdInit(void) { _delay_loop_(1000);//延时等待 LcdSpiSetup(); /*--------------------------------------------------- LCD模块上电等待延时 ----------------------------------------------------*/ _delay_loop_(1000);//延时等待 LcdClearBuffer(); LcdSendCommand(0x20);//发送4位控制命令 // LcdSendCommand(0x30);//发送8位控制命令//与8位4位无关!!! LcdSendCommand(0x02);//发送位址归位命令,设定DDRAM位址计数器为0 LcdSendCommand(0x04);//发送进入点命令 LcdSendCommand(0x0c);//发送开显示关光标命令 LcdSendCommand(0x01);//发送清除显示命令 LcdSendCommand(0x80);//发送设定DDRAM地址0x00命令 //Keil C51汉字0xfd出错测试 // SetLcdDisplayPos(0, 0);//汉字定位到上行左端 // LcdDisplay("褒饼昌除待谍洱俘"); // LcdDisplay("1234567812345678"); // SetLcdDisplayPos(1, 0);//汉字定位到上行左端 // LcdDisplay("庚过糊积箭烬君魁"); // LcdDisplay("1234567812345678"); // SetLcdDisplayPos(2, 0);//汉字定位到上行左端 // LcdDisplay("例笼慢谬凝琵讫驱"); // LcdDisplay("1234567812345678"); SetLcdDisplayPos(3, 0);//汉字定位到上行左端 LcdDisplay("三升数她听妄锡淆"); // LcdDisplay("1234567812345678"); } void LcdObj::LcdSend(unsigned char cData) { cData &= 0xff; #if (ccsdebug == 0) McBSP1->DXR1 = cData;//发送串行数据或命令 _delay_loop_(1);//延时等待 McBSP1->SPSA = SPCR2; while((McBSP1->SPSD & (1 << SPCR2_XRDY)) == 0) {//等待发送结束 __nop(); __nop(); } _delay_loop_(1);//延时等待 #else unsigned int i; McBSP1->SPSA = PCR; for (i = 0; i < 8; i ++) { McBSP1->SPSD &= ~(1 << PCR_CLKXP);//CLKX信号=0 _delay_loop_(1);//延时等待 if (cData & 0x80) {//MSB最高位为1时 McBSP1->SPSD |= (1 << PCR_DX_STAT);//DX信号=1 } else { McBSP1->SPSD &= ~(1 << PCR_DX_STAT);//DX信号=0 } cData <<= 1; _delay_loop_(1);//延时等待 McBSP1->SPSD |= (1 << PCR_CLKXP);//CLKX信号=1 _delay_loop_(1);//延时等待 } McBSP1->SPSD |= (1 << PCR_DX_STAT);//DX信号=1 _delay_loop_(1);//延时等待 #endif } /*-------------------------------------------------------- 发送8位LCD控制命令 --------------------------------------------------------*/ //__inline void LcdObj::LcdSendCommand(unsigned char cCommand) { /*-------------------------------------------------------- 发送同步脉冲11111 WR(0) RS(0) 0发送顺序从左至右) --------------------------------------------------------*/ #if (ccsdebug == 1) McBSP1->SPSD |= (1 << PCR_FSXP);//IO模拟控制FSX信号=1 _delay_loop_(1);//延时等待 #endif LcdSend(0xf8);//发送LCD控制命令 LcdSend(cCommand & 0xf0);//发送高4位LCD控制命令 LcdSend((cCommand << 4) & 0xff);//发送低4位LCD控制命令 #if (ccsdebug == 1) McBSP1->SPSD &= ~(1 << PCR_FSXP);//IO模拟控制FSX信号=0 #endif if (cCommand == 0x01) _delay_loop_(160);//延时等待 else _delay_loop_(72);//st7920要求等待72uS } /*-------------------------------------------------------- 发送8位LCD显示数据 --------------------------------------------------------*/ //__inline void LcdObj::LcdSendData(unsigned char cData) { cData &= 0xff; /*-------------------------------------------------------- 发送同步脉冲11111 WR(0) RS(0) 0发送顺序从左至右) --------------------------------------------------------*/ #if (ccsdebug == 1) McBSP1->SPSD |= (1 << PCR_FSXP);//IO模拟控制FSX信号=1 _delay_loop_(1);//延时等待 #endif LcdSend(0xfa);//发送LCD显示数据 LcdSend((cData & 0xf0) & 0xff);//发送高4位LCD显示数据 LcdSend((cData << 4) & 0xff);//发送低4位LCD显示数据 #if (ccsdebug == 1) McBSP1->SPSD &= ~(1 << PCR_FSXP);//IO模拟控制FSX信号=0 #endif _delay_loop_(72);//st7920要求等待延时72uS } //__inline void LcdObj::SetLcdDisplayPos(unsigned int row, unsigned int col) { row &= 0x03;//LCD12864为4行汉字 col &= 0x0f;//每行8个汉字16个字符 LcdRow = row; LcdCol = col; LcdRowWriteEnable[row] = true;//允许此行刷新汉字显示 } //__inline void LcdObj::LcdClearBuffer(void) { unsigned int i, j; for (i = 0;i < 4;i ++) { for (j = 0;j < 16; j ++) { LcdBuffer[j] = ' '; } LcdRowWriteEnable = true;//允许此行刷新汉字显示 } LcdRow = 0; LcdCol = 0; } //__inline void LcdObj::LcdDisplayBuffer(void) { unsigned int i, j; for (i = 0; i < 4; i ++) {//LCD12864为4行汉字 if (LcdRowWriteEnable) {//允许此行刷新汉字显示 LcdSendCommand(0x80 + (i & 1) * 16 + (i >> 1) * 8);//移动光标 _delay_loop_(1);//延时等待 for (j = 0; j < 16; j ++) {//每行8个汉字16个字符 LcdSendData(LcdBuffer[j]);//刷新显示字符 _delay_loop_(1);//延时等待 } LcdRowWriteEnable = false;//过后不允许此行刷新汉字显示 _delay_loop_(1);//延时等待 } } } //__inline void LcdObj::LcdDisplay(const char * string) { while(*string) { LcdBuffer[LcdRow][LcdCol ++] = (unsigned char)*string ++; } } void LcdObj::LcdDisplay(unsigned char ch) { LcdBuffer[LcdRow][LcdCol ++] = ch; if (LcdCol >= 16) { LcdRow ++;//换行 LcdCol = 0;//回车 } else { LcdRowWriteEnable[LcdRow] = true;//允许此行刷新汉字显示 } LcdCol &= 0x0f; LcdRow &= 3; } void LcdObj::LcdDisplay(double val) { char string[17]; std::sprintf(string, "%5.2f", val);//注意std:: LcdDisplay(string); } void LcdObj::LcdDisplay(unsigned int val) { char string[17]; std::sprintf(string, "%04X", val);//注意std:: LcdDisplay(string); } void LcdObj::LcdDisplay(unsigned long val) { //char string[17]; LcdDisplay((unsigned int)(val >> 16)); LcdDisplay((unsigned int)(val & 0xffff)); // std::sprintf(string, "%08LX", (unsigned long)val);//注意std:: // LcdDisplay(string); } void LcdObj::LcdDisplay(unsigned char hexstr[], unsigned int len) { unsigned char ch; for (int i = 0; i < len; i ++) { ch = *hexstr++; if (ch < 0xa0) { LcdBuffer[LcdRow][LcdCol ++] = (ch >> 4) + '0'; } else { LcdBuffer[LcdRow][LcdCol ++] = (ch >> 4) - 10 + 'A'; } if ((ch & 0x0f) < 0x0a) { LcdBuffer[LcdRow][LcdCol ++] = (ch & 0x0f) + '0'; } else { LcdBuffer[LcdRow][LcdCol ++] = (ch & 0x0f) - 10 + 'A'; } } } UartObj::UartObj(void) { UartInit(); } void UartObj::UartInit(void) { Start = false;//还未进行自适应 Count = 0; PRDREG = 0; RxCount = 0; Status = 0; RWCount = 0; RRCount = 0; } unsigned int UartObj::TestBio(void) { unsigned int PortBIO = 0;//BIO引脚为低电平 asm(" bc __TestBio__1,BIO"); PortBIO = 0x200;//BIO引脚为高电平 asm("__TestBio__1"); return PortBIO; } void UartObj::UartExec(void) { unsigned long timerH, timerL, timer; if (!Start) {//波特率测试 TIMER1->TCR |= (1 << TCR_TSS);//关闭定时器1 TIMER1->TIM = TIMER1->PRD; TIMER1->TCR &= ~(1 << TCR_TSS);//启动定时器1 SREG->IFR = (1 << IFR_TINT1);//清除TINT1中断标志 while(!(SREG->IFR & (1 << IFR_TINT1))) { if (TestBio()) {//等待BIO上跳 TIMER1->TCR |= (1 << TCR_TSS);//关闭定时器1 PRDREG = TIMER1->PRD - TIMER1->TIM;//存时间基准 timer = (unsigned long)(PRDREG); TIMER1->TIM = TIMER1->PRD;//0xffff TIMER1->TCR &= ~(1 << TCR_TSS);//启动定时器1 SREG->IFR = (1 << IFR_TINT1);//清除TINT1中断标志 timerH =0L; while(TestBio()) { if (SREG->IFR & (1 << IFR_TINT1)) { TIMER1->TCR |= (1 << TCR_TSS);//关闭定时器1 timerH += 0xffff; TIMER1->TIM = TIMER1->PRD; TIMER1->TCR &= ~(1 << TCR_TSS);//启动定时器1 SREG->IFR = (1 << IFR_TINT1);//清除TINT1中断标志 if (timerH >= (6 * timer + (6 * timer * 3 / 100))) return;//高电平太宽(6.5) } } TIMER1->TCR |= (1 << TCR_TSS);//关闭定时器1 timerH += TIMER1->PRD - TIMER1->TIM; TIMER1->TIM = TIMER1->PRD;//0xffff TIMER1->TCR &= ~(1 << TCR_TSS);//启动定时器1 if (timerH >= (6 * timer + (6 * timer * 3 / 100))) return;//高电平太宽(6.5) if (timerH <= (6 * timer - (6 * timer * 3 / 100))) return;//高电平太宽(5.5) timerL = 0; while(!TestBio()) { if (SREG->IFR & (1 << IFR_TINT1)) { TIMER1->TCR |= (1 << TCR_TSS);//关闭定时器1 timerL += 0xffff; TIMER1->TIM = TIMER1->PRD; TIMER1->TCR &= ~(1 << TCR_TSS);//启动定时器1 SREG->IFR = (1 << IFR_TINT1);//清除TINT1中断标志 if (timerL >= (2 * timer + (2 * timer * 3 / 100))) return;//高电平太宽(2.5) } } TIMER1->TCR |= (1 << TCR_TSS);//关闭定时器1 timerL += TIMER1->PRD - TIMER1->TIM; TIMER1->TIM = TIMER1->PRD;//0xffff TIMER1->TCR &= ~(1 << TCR_TSS);//启动定时器1 if (timerL >= (2 * timer + (2 * timer * 3 / 100))) return;//高电平太宽(2.5) if (timerL <= (2 * timer - (2 * timer * 3 / 100))) return;//高电平太宽(1.5) TIMER1->PRD = timerH / 6; Count = 0; Status = 0; RxCount = 0; RWCount = 0; RRCount = 0; Start = true; } } } else { TIMER1->TCR |= (1 << TCR_TSS);//关闭定时器1 TIMER1->TIM = TIMER1->PRD / 2;//起始位为1/2,其它位为1/1 TIMER1->TCR &= ~(1 << TCR_TSS);//启动定时器1 SREG->IFR = (1 << IFR_TINT1);//清除TINT1中断标志 SREG->IMR &= ~(1 << IMR_INT0);//禁止INT0中断 SREG->IMR |= (1 << IMR_TINT1);//允许TINT1中断 Status |= ((unsigned int)1 << Uart_BUSY); Count = 0;//从起始位开始 } } void UartObj::UartRecExec(void) { Count ++;//接收到1位起始位或数据或停止位,计数进行节拍管理。 DDRX >>= 1;//右移串行数据位 DDRX |= TestBio();//取串口接收数据位 if (Count >= (8 + 2)) {//串口数据位最后位停止位 if (((DDRX & (1 << BIT0)) == 0) && (DDRX & (1 << BIT9))) {//接收够8位数据 DDR = (DDRX >> 1) & 0xff;//去除起始位和终止位后截取8位数据 RxBuff[RWCount] = DDR;//写入接收FIFO. RWCount ++;//指向下1位数据 RWCount &= 0x3f;//64个字节 RxCount ++;//接收字节个数计数 if (RxCount > 64) { Status |= (1 << Uart_OE);//数据溢出,覆盖了FIFO } else { Status &= ~(1 << Uart_OE);//数据未溢出 } Status |= (1 << Uart_RDR);//FIFO里有数据 } TIMER1->TCR |= (1 << TCR_TSS);//关闭定时器1 SREG->IMR &= ~(1 << IMR_TINT1);//禁止TINT1中断 SREG->IMR |= (1 << IMR_INT0);//允许INT0中断 SREG->IFR = (1 << IFR_INT0);//清除INT0中断标志 Status &= ~(1 << Uart_BUSY);//串口闲 } } unsigned char UartObj::Getchar(void) { unsigned char ch; while (!(Uart.Status & (1 << Uart_RDR)));//等待接收缓冲区有数据 Disable();//关中断 ch = RxBuff[RRCount];//取串口数据 RRCount ++;//指向下1位数据 RRCount &= 0x3f;//64个字节 RxCount --; if (RxCount == 0) { Uart.Status &= ~(1 << Uart_RDR);//FIFO里已无数据 } Enable();//开中断 return ch;//返回接收数据 } int main(void) { unsigned char ch; Enable();//开中断 Lcd.SetLcdDisplayPos(0, 0); while(1) { if (::IOXF) { SREG->ST1 |= (1 << ST1_XF); } else { SREG->ST1 &= ~(1 << ST1_XF); } // idle(); ch = Uart.Getchar(); if (ch >= ' ') { Lcd.LcdDisplay(ch); } } } interrupt void Timer0Isr() { static int count = 0; static unsigned int ledcount = 0; //char str[17]; count ++; if (count >= 500) { count = 0; // Lcd.SetLcdDisplayPos(0, 0); // std::sprintf(str, "ledcount=%04X ", ledcount >> 2);//注意std:: // Lcd.LcdDisplay("ledcount="); // Lcd.LcdDisplay(ledcount >> 2); Lcd.LcdDisplayBuffer();//刷新LCD显示缓冲区 /* Lcd.SetLcdDisplayPos(3, 0); if ((ledcount & 0x03) == 0) { Lcd.LcdDisplay("12345678"); Lcd.SetLcdDisplayPos(3, 8); Lcd.LcdDisplay("我晕倒了"); } else { Lcd.LcdDisplay("你在倒塌"); Lcd.SetLcdDisplayPos(3, 8); Lcd.LcdDisplay("87654321"); } */ ::IOXF = !::IOXF;//郁闷~~~中断中ST1被保护~~~ ledcount ++; } } interrupt void Timer1Isr() {//串口Uart的软时? Uart.UartRecExec(); SREG->IFR = (1 << IFR_TINT1);//清除TINT1中断标志 } interrupt void Eint0Isr() { Uart.UartExec(); SREG->IFR = (1 << IFR_INT0);//清除INT0中断标志 } interrupt void Eint1Isr() { // Lcd.SetLcdDisplayPos(2, 0); // Lcd.LcdDisplay("欢迎INT1中断观光"); SREG->IFR = (1 << IFR_INT1);//清除INT1中断标志 } interrupt void Eint2Isr() { // Lcd.SetLcdDisplayPos(2, 0); // Lcd.LcdDisplay("欢迎INT2中断观光"); SREG->IFR = (1 << IFR_INT2);//清除INT2中断标志 } interrupt void Eint3Isr() { // Lcd.SetLcdDisplayPos(2, 0); // Lcd.LcdDisplay("欢迎INT3中断观光"); SREG->IFR = (1 << IFR_INT3);//清除INT3中断标志 }