打印

大家帮我看看这个IO口模拟串口程序有什么问题

[复制链接]
1693|16
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
HDEYY|  楼主 | 2013-12-8 19:18 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char

sbit txd=P1^0;
sbit rxd=P1^1;
uint input,flag;

void wait()   //数据传输等待
{
while(!flag);
flag=0;
}

void init() //初始化程序
{
flag=0;
TMOD=0X02;    //定时器0,工作方式2:8位自动重装
TH0=0xC0;   //256-96=0xa0;(波特率9600:1000000/9600/(12/11.0592)us)
TL0=0XC0;   
TR0=0;
TF0=0;
}

void rece()
{  
uchar i=8;
TH0=0XA0;
TL0=0XA0;

TR0=1;   //开起定时器等待起始位
input=0;
wait();
while(i--)  //接收8位数据
{
input>>=1;   //将收到的数据往低位推
if(rxd==1)
input|=0x80;
else
input|=0x00;
wait();
}
while(!flag)   //检验停止位
{
if(rxd)
break;
}

TR0=0;
P0=input;
}
void send(char output)
{
uchar j=8;
TH0=0XA0;
TL0=0XA0;

txd=(bit)0;  //发送起始位
TR0=1;
wait();

while(j--)  //发送8未数据
{
txd=(bit)(output&0x01);
output>>=1;
wait();
}  //发送停止位
txd=(bit)1;
wait();
TR0=0;
}

void main()
{
init();
while(1)
{
if(rxd==0)
rece(); //电脑用串口调试发送数据,然后在p0口的led上显示
send(P0);  //将P0口数据反馈回电脑,并在串口调试上显示

}
}
void ser() interrupt 1
{
flag=1;
}



电脑上没有显示返回值,led也不变化,这是怎么回事

相关帖子

沙发
yangfan19641964| | 2013-12-9 10:06 | 只看该作者
你这样不行吧?软件串口要用汇编编程。

使用特权

评论回复
板凳
yangfan19641964| | 2013-12-9 10:11 | 只看该作者
                CSEG        AT        000BH

                JNB                T_R,SOFT_RECEIVE
                LJMP        SOFT_SEND

/*********************************************/


                CSEG        AT        0040H




/*********************************************/
SOFT_RECEIVE:
                JBC                UART_Wait,SOFT_INITIAL

                PUSH        ACC
                PUSH        PSW

                CLR                A
                MOV                C,RXD2
                RLC                A
                MOV                C,RXD2                                        ;12
                RLC                A
                MOV                C,RXD2
                RLC                A
                ADD                A,#SOFT_TABLE-$-3
                MOVC        A,@A+PC

                JBC                UART_First,SOFT_START

                MOV                C,P
                MOV                A,rece_shift
                RRC                A
                MOV                rece_shift,A

                DJNZ        R8,SOFT_DIRECT_RETI


                MOV                r_data,A
;                MOV                SBUF2r,A
;                SETB        RI2


                CLR                TR0
                MOV                TMOD,#26H
                MOV                TL0,#0FFH
                SETB        TR0
                SETB        UART_Wait

                PUSH        P1
                CLR                SEL1
                CLR                SEL2
                LCALL         UARTreceiver
                POP                P1


SOFT_DIRECT_RETI:
                POP                PSW
                POP                ACC
                RETI

SOFT_TABLE:
                DB                00H                ;00000000B
                DB                00H                ;00000001B
                DB                00H                ;00000010B
                DB                01H                ;00000011B
                DB                00H                ;00000100B
                DB                01H                ;00000101B
                DB                01H                ;00000110B
                DB                01H                ;00000111B

SOFT_START:

                JB                P,START_ERROR

                MOV                R8,#8
                POP                PSW
                POP                ACC
                RETI

START_ERROR:               
                CLR                TR0
                MOV                TMOD,#26H
                MOV                TL0,#0FFH
                SETB        TR0
                SETB        UART_Wait

                POP                PSW
                POP                ACC
                RETI

SOFT_INITIAL:
                CLR                TR0
                MOV                TMOD,#22H
                MOV                TL0,#256 - 96 +29                ;10+12
                SETB        TR0
                SETB        UART_First
                RETI                                                         ;13

/*********************************************/
SOFT_SEND:
                RETI

使用特权

评论回复
地板
ayb_ice| | 2013-12-9 10:49 | 只看该作者
这种模拟核心还是中断中操作吧
另外不建议用循环处理,还是展开为好
另外要在标准信号的中间采样,假设位周期是1ms,那么分别在0.5ms,1.5ms,2.5ms采样。。。

使用特权

评论回复
5
NE5532| | 2013-12-9 13:16 | 只看该作者
以51的资源,中断的方式模拟串口,100uS的中断频率,还是有点吃不消的。强烈建议楼主优化应用,用软件延时的线性程序来写。

使用特权

评论回复
6
ayb_ice| | 2013-12-9 13:48 | 只看该作者
我说的中断是
开始信号进入中断后,不出中断,直接在中断中接收或发送完一字节数据后再出中断

使用特权

评论回复
7
yangfan19641964| | 2013-12-9 14:22 | 只看该作者
不用中断?关键在于要准守设定的波特率、严格按照时间节点采样。更优化的是遵照硬件串口的冗余采样:三次,三中取二。

没有做过的就不要乱发言了。误导别人。

使用特权

评论回复
8
q1625334| | 2013-12-9 14:33 | 只看该作者
表示新人还在学校实习中

使用特权

评论回复
9
ayb_ice| | 2013-12-9 14:36 | 只看该作者
yangfan19641964 发表于 2013-12-9 14:22
不用中断?关键在于要准守设定的波特率、严格按照时间节点采样。更优化的是遵照硬件串口的冗余采样:三次, ...

不用中断,开什么玩笑
一个实际项目不可能没有其它中断,请问怎样保证一定可以接收,可以正确接收

使用特权

评论回复
10
yklstudent| | 2013-12-9 14:37 | 只看该作者
一个外部中断加一个定时器可以完成

使用特权

评论回复
11
NE5532| | 2013-12-9 15:45 | 只看该作者
中断是必须用的,至少需要一个端口电平变化中断。到是不一定要用汇编,C语言把优化关闭掉也可以用。冗余采样不是必须,毕竟板卡级条件下,信号被干扰的还是很罕见的事情。

使用特权

评论回复
12
yangfan19641964| | 2013-12-10 13:43 | 只看该作者
yklstudent 发表于 2013-12-9 14:37
一个外部中断加一个定时器可以完成

用T0管脚做为串行输入端,初始化将T0设置为计数器方式2(初值为0FFH)。只要对方发开始位,则被识别进入T0中断。进去后再将T0改为定时器。接收完一个字节后重新改回计数器。这样可以节约资源。

使用特权

评论回复
13
yangfan19641964| | 2013-12-10 13:49 | 只看该作者
NE5532 发表于 2013-12-9 15:45
中断是必须用的,至少需要一个端口电平变化中断。到是不一定要用汇编,C语言把优化关闭掉也可以用。冗余采 ...

在一个实际应用环境下,干扰恐怕难免。当然,不用冗余将大大减少指令、极大地提高速度。

用软件方式模拟串口确实会大量占用软件时间,这也是没奈何的事。这需要对整个产品进行总体设计、系统设计。此外,可以提高晶振(对于STC单片机还可以额外选6T模式);如果这样,那么8位定时器会不够用。解决方法:1  改成T2定时器  2 精心编程、16位T0定时器照样能准确定时。

使用特权

评论回复
14
ayb_ice| | 2013-12-10 14:15 | 只看该作者
yangfan19641964 发表于 2013-12-10 13:43
用T0管脚做为串行输入端,初始化将T0设置为计数器方式2(初值为0FFH)。只要对方发开始位,则被识别进入T ...

这个方法还不错

使用特权

评论回复
15
yklstudent| | 2013-12-10 19:23 | 只看该作者
yangfan19641964 发表于 2013-12-10 13:43
用T0管脚做为串行输入端,初始化将T0设置为计数器方式2(初值为0FFH)。只要对方发开始位,则被识别进入T ...

感觉接受发送受限制了

使用特权

评论回复
16
HDEYY|  楼主 | 2013-12-10 22:01 | 只看该作者
谢谢各位的回复,中断的确忘了开,可是开了也没用。

不过今天刚刚找到问题,应为flag没有定义为volatile uchar flag,所以编译器会对flag进行优化,导致flag读取错误,(flag是不稳定的)

下面是我改进的,贴出来大家分享
只能收发十六进制数和单个字节
#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char

sbit txd=P1^0;
sbit rxd=P1^1;
uchar input;
volatile uchar flag; // 什么的Flag???   Timer_Period_Flag

//   每一位等待时间
//   TxRx_Bit_Wait()
//  描述???
void wait()                                          //数据传输等待
{
        while(!flag);
        flag=0;
}
// 什么初始化
void init()                                        //初始化程序
{
        flag=0;
        TMOD=0X02;                           //定时器0,工作方式2:8位自动重装
        TH0=0xA0;                          //256-96=0xa0;(波特率9600:1000000/9600/(12/11.0592)us)
        TL0=0XA0;                                  
        TR0=0;
        TF0=0;
        EA=1;
        ET0=1;
}

void rece()
{                                        
        uchar i=8;
        TH0=0XA0;
        TL0=0XA0;

        TR0=1;                                                          //开起定时器等待起始位
        input=0;
        wait();
        while(i--)                                                 //接收8位数据
        {
                input>>=1;                                          //将收到的数据往低位推
                if(rxd==1)
                        input|=0x80;
                else
                        input|=0x00;
                wait();
        }
        while(!flag)                                                  //检验停止位
        {

                if(rxd)
                        break;
        }

        TR0=0;                                       
        P0=input;
}
void send(char output)
{
        uchar j=8;               
        TH0 = 0XA0;         
        TL0 = 0XA0;
        TR0 = 1;
        txd=(bit)0;                                                 //发送起始位
       
        wait();

        while(j--)                                                 //发送8未数据
        {
                txd=(bit)(output&0x01);
                output>>=1;
                wait();       
        }                                                                 
        txd=(bit)1;                                                                //发送停止位
        wait();
        TR0=0;
}

void main()
{
        init();
        while(1)
        {
                if(rxd==0)
                {                                       
                rece();                                                //电脑用串口调试发送数据,然后在p0口的led上显示
                send(P0);                                         //将P0口数据反馈回电脑,并在串口调试上显示
            }
        }
}
void ser() interrupt 1
{
        flag=1;       
}

使用特权

评论回复
17
adef_13| | 2013-12-11 08:02 | 只看该作者
好难     

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

10

帖子

1

粉丝