pca 制作 soft uart 具有一定的优势,(微型系统小数据量传输),成本低联,当然他的弱点也很明显,就是占用资源,公司的工程师在
新华龙的芯片上成功应用了这项技术,我在网上偶然发现p89v51rd2也具有pca阵列,于是想移植到其上,但是发现了一个问题,有可能是
对芯片掌握不够造成的,希望大家指点迷津,下面是我的代码,测试是在stc的下在板上进行的,经振18.432m,程序的关键部分是,数据发
送过程的模拟,以状态机的形式在程序里体现,在软串口的应用上使用了大量标志位,实际上和硬件uart是一致的,PCA模块1是发送模块
我的ccf1标志位始终不能被手动清零,程序就是发送11个数据,我的软串口上拉了一个LED,发送时应该闪亮,可是他一直亮,说明数据没有发送
下面是我的代码大家分析一下,错在那里?
//设计要求实现普通96/n/8/1通信10位数据 V1 //实现全双工,使用cex0,cex1
#include <REG51F.h> #include <stdio.h>
#define uchar unsigned char #define uint unsigned int
#define BAUD_RATE 9600 // Baud rate of UART in bps
#define SYSCLK 18432000 // SYSCLK frequency in Hz
#define TIME_COUNT SYSCLK/BAUD_RATE/6 // 对应一个位时间的PCA计数值(PCA 配置为对SYSCLK/6计数)
#define TH_TIME_COUNT TIME_COUNT*3/2 // 3/2位时间用于接收到一个起始位后在起始位边沿之后RX应在一个
bit SRI1; // SW_UART 接收完成标志 bit STI1; // SW_UART 发送完成标志
bit SREN; // SW_UART 用户级中断支持允许 bit SES1;
bit SREN1; // SW_UART 接收允许 bit STXBSY1; // SW_UART 发送忙标志
bit SW_DONE; //发送完15个数据标志
sbit SW1_RX = P1^3; // SW_UART 接收 sbit SW1_TX = P1^4; // SW_UART 发送
sbit tt = P3^3;
#define Uart1Tbuf_RAM 0x0E00
uchar SW_Uart1TNum;
uchar TDR1; // SW_UART 发送数据寄存器 uchar RDR1; // SW_UART 接收数据寄存器
uchar SUTXST1 = 0; // SW_UART TX状态变量 uchar SURXST1 = 0; // SW_UART RX状态变量
uchar RXSHIFT1= 0; // SW_UART RX移位寄存器
void PCA_ISR(); // SW_UART 中断服务程序 void PCA_TEST(void); // SW_UART 中断方式测试程序 void USER_ISR(void); // SW_UART 测试中断服务程序 void SW_UART_INIT(); // SW_UART 初始化程序 void SW_UART_ENABLE(); // SW_UART 允许程序
/************************************************************************/
void SW_UART_INIT(void)
{
CCON = 0x00; CMOD |= 0x02; CCAPM0 = 0x10;
CCAP0L = 0x00; CCAP0H = 0x00;
CCF0 = 0; // 清除被挂起的PCA模块0和模块1捕捉/比较中断 CCF1 = 0; SRI1 = 0; // 清除接收完成标志 STI1 = 0; // 清除发送完成标志
SW1_TX = 1; // TX线初始化为高电平 STXBSY1 = 0; // 清除SW_UART忙标志 }
/************************************************************************/
void SW_UART_ENABLE(void) //ok
{ CCAPM0 |= 0x01; // 允许PCA模块0接收中断 CCAPM1 |= 0x01; // 允许PCA模块1发送中断
CR = 1; // 启动PCA计数器
IE = IE | 0x40; }
/************************************************************************/
PCA_ISR() interrupt 6 using 1
{ unsigned int PCA_TEMP; // 临时存储变量用于处理PCA模快高和低字节
if (CCF0) // 首先检查接收中断变量如果CCF0置位则对其服务 { CCF0 = 0; // 清除中断标志
/***************************************************************************************/
if (SURXST1==0){ //状态0
if (SREN1 && (SW1_RX==0)) //检查接收允许和起始位是否正确 { PCA_TEMP = (CCAP0H << 8); // 将模块0内容读到 PCA_TEMP |= CCAP0L; // PCA_TEMP PCA_TEMP += TH_TIME_COUNT; // 加3/2位时间到PCA_TEMP CCAP0L = PCA_TEMP; // 用新值恢复PCA0CPL0和PCA0CPH0 CCAP0H = (PCA_TEMP >> 8); CCAPM0 = 0x49; // 将模块0切换到软件定时器方式允许中断 SURXST1++; // 更新RX状态变量 } }
/***************************************************************************************/
else if (SURXST1==9) //状态9 { RDR1 = RXSHIFT1; // 将接收到的数据传送到接收寄存器 SRI1 = 1; // 置1接收完成标志 CCAPM0 = 0x11; // 切换模块0到负沿捕捉方式允许中断以检测起始位 SURXST1 = 0; // 复位RX状态变量 if (SES1){ // 如果用户级中断支持被允许 IE |= 0x84; // 通过允许并强制 模拟UART发送中断(借用外部中断1) tt =0; // 外部中断激活(测试通过) } // 可将硬件P3^3直接接地(未测)需要考虑。。。。 }
/***************************************************************************************/ else if (SURXST1<9) //状态1-8 { RXSHIFT1 = RXSHIFT1 >> 1; // 右移一位 if (SW1_RX==1) // If SW0_RX=1 { RXSHIFT1 |= 0x80; // 将'1'移入RXSHIFT的msb } else { RXSHIFT1 &= ~0x80; // 将'1'移入RXSHIFT的msb } PCA_TEMP = (CCAP0H << 8); // 将模块0内容读到PCA_TEMP PCA_TEMP |= CCAP0L; PCA_TEMP += TIME_COUNT; // 加一个位时间到PCA_TEMP CCAP0L = PCA_TEMP; // 用新值恢复PCA0CPL0和PCA0CPH0 CCAP0H = (PCA_TEMP >> 8); SURXST1++; // 更新RX状态变量 }
/***************************************************************************************/ else // 出错处理 { CCAPM0 = 0x11; // 切换模块0到负沿捕捉方式允许中断以检测起始位 SURXST1=0; } }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
else if (CCF1){ // 检查发送中断如果CCF3置位则对其服务
CCF1 = 0; // 清除中断标志
/***************************************************************************************/
if (SUTXST1==0) { SW1_TX = 0; // 使TX引脚变低作为起始位 PCA_TEMP = CCAP0L; // 将PCA计数器的值读到PCA_TEMP PCA_TEMP |= (CCAP0H<< 8); PCA_TEMP += TIME_COUNT; // 加一个位时间 CCAP1L = PCA_TEMP; // 将更新后的匹配值存到 CCAP1H = (PCA_TEMP >> 8); // 模块1捕捉比较寄存器 CCAPM1 |= 0x48; // 允许模块1软件定时器 SUTXST1++; // 更新TX状态变量 }
/***************************************************************************************/
else if(SUTXST1==11) { STI1 = 1; // 表示发送完成 SUTXST1 = 0; // 复位TX状态 SW1_TX = 1; // SW_TX应保持高电平 CCAPM1 = 0x01; // 禁止模块1软件定时器保持中断为允许状态以备下一次传输 if (SES1){ //如果用户级中断支持被允许: IE |= 0x84; // 通过允许并强制 模拟UART发送中断(借用外部中断1) tt =0; // 外部中断激活(测试通过) } STXBSY1 = 0; // SW_UART TX空闲 } /***************************************************************************************/ else if(SUTXST1==10) // 发送停止位 { SW1_TX = 1; // 输出停止位 1 PCA_TEMP = (CCAP1H << 8); // 将模块1内容读到PCA_TEMP PCA_TEMP |= CCAP1L; PCA_TEMP += TIME_COUNT; // 加一个位时间到PCA_TEMP CCAP1L = PCA_TEMP; // 用新值恢复PCA0CPL1 CCAP1H = (PCA_TEMP >> 8); // 和PCA0CPH1 SUTXST1++; // 更新TX状态变量 }
/***************************************************************************************/
else if(SUTXST1<10) { SW1_TX = (TDR1 & 0x01); // 将TDR的LSB输出到SW_TX引脚 TDR1 >>= 1; // TDR右移一位 // 将一个'1'移入TDR的MSB作为状态9的停止位 PCA_TEMP = (CCAP1H << 8); // 将模块1内容读到PCA_TEMP PCA_TEMP |= CCAP1L; PCA_TEMP += TIME_COUNT; // 加一个位时间到PCA_TEMP CCAP1L = PCA_TEMP; // 用新值恢复PCA0CPL1 CCAP1H = (PCA_TEMP >> 8); // 和PCA0CPH1 SUTXST1++; // 更新TX状态变量 } else // 出错处理 { SUTXST1 = 0; // 复位TX状态 SW1_TX = 1; // SW_TX应保持高电平 CCAPM1 = 0x01; // 禁止模块1软件定时器保持中断为允许状态以备下一次传输 } } CF=0; }
void PCA_START(void) { SW_UART_INIT(); // 初始化SW_UART SW_UART_ENABLE(); // 允许SW_UART
CCAPM1 = 0x48; CCAP1L = 0x00; CCAP1H = 0x00; EA=1; SES1 = 1; // 允许用户级中断支持 STI1=1; // 指示发送完成以启动下一次传输 SREN1 = 1; // 允许SW_UART接收器 IE |= 0x84; tt =0; }
//void SW_UART_ISR(void) interrupt 11 // 借用比较器0中断!!! USER_ISR() interrupt 2 { uchar xdata *Read_Buff; IE &= 0x80; if (STI1){ STI1 = 0; // 清楚发送标志 Read_Buff=Uart1Tbuf_RAM; STXBSY1 = 1; // 申请SW_UART发送器 TDR1=Read_Buff[SW_Uart1TNum]; //将串口0发送缓存中的一个字节 SW_Uart1TNum--; CCF1 = 1; // 强制模块1中断以启动发送 }
if (STI1|SRI1) // 如果SRI或STI置位再次触发 { // STI1 = 0;
IE |= 0x84; tt =0; } else { IE = 0x00; tt =1;
} }
READ_MK_DATA(){ // 获取数据命令 uchar data i; uchar xdata *Sent_Buff; Sent_Buff=Uart1Tbuf_RAM; Sent_Buff[0]=0X7E; Sent_Buff[1]=0X30; Sent_Buff[2]=0X31; Sent_Buff[5]=0X31; Sent_Buff[6]=0X31; Sent_Buff[7]=0X20; Sent_Buff[8]=0X20; Sent_Buff[9]=0X20; Sent_Buff[10]=0X20;
SW_Uart1TNum=11; STI1=1; IE |= 0x84; tt =0; }
main( )
{
IP=0x40;
PCA_START();
READ_MK_DATA();
while(1)
{}
}
|