51单片机串口通信问题。
预期实现功能:单片机通过两外部中断计数外部脉冲。两计数脉冲可在数码管上显示。脉冲数可由按键或指令flag发送至PC。
出现问题为:不管单片机一何种方法向PC发送数据,只要有外部干扰,能自动向PC发送数据。数码管上显示的数值并不是按我想的15s变化一次。为什么?
#include <reg52.h>
#include <string.h>
#define uchar unsigned char
#define uint unsigned int
sbit M_RE= P2^5; //接收器低电平有效
sbit M_DE= P2^6; //驱动器高电平有效
sbit KEY1 = P3^2; //按键S19
uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};
sbit HC138A0 = P2^0;
sbit HC138A1 = P2^1;
sbit HC138A2 = P2^2;
uchar led[8];
sbit D1=P1^0;
sbit flag=P1^1; //单片机是否收到主机发过来的指令
int Num1=0,Num2=0;m=0,D_all=0,X_all=0;
/****************************/
//初始化设置
void coun()
{
EA=1; //开总中断
EX0=1; //开外部中断0
EX1=1; //开外部中断1
IT0=1; //外部中断0的中断触发控制位:此为下降沿触发方式。
IT1=1; //外部中断1的中断触发控制位:此为下降沿触发方式。
ET0=1; //开定时/计数器T0中断
TR0=1; //T0运行控制位,置1,开始工作。
TMOD=0x01; //T0定时,工作方式选择方式1。
TH0=(65536-50000)/256; //一个机器周期时间为1/11.0592*12=1.085us 50000机器周期时间为50000*1.085us=54.25ms
TL0=(65536-50000)%256;
}
//初始化串口
void init_serialcomm( void )
{
SCON = 0x50 ; //SCON: serail mode 1, 8-bit UART, enable ucvr 串口模式1,允许接收(选择串口的工作方式和某些控制功能)
TMOD = 0x20 ; //TMOD: timer 1, mode 2, 8-bit reload 定时1,方式2,
PCON = 0x80 ; //SMOD=1 波特率提高一倍
TH1 = 0xFa ; //Baud:9600 fosc=11.0592MHz
// IE = 0x90 ; //Enable Serial Interrupt 允许串口中断
TR1 = 1 ; // timer 1 run // TI=1;
ES=1;
EA=1;
}
//延时函数
void delay(int z)
{
unsigned char x,y;
for(x=0;x<50;x++)
for(y=z;y>0;y--) ;
}
//1ms延时
void Delay_1ms(uint i)
{
uchar x,j;
for(j=0;j<i;j++)
for(x=0;x<=148;x++);
}
//向串口发送一个字符
void send_char_com( unsigned char ch)
{
SBUF=ch;
while (TI== 0 );
TI= 0 ;
}
//向串口发送一个数组,length为该数组长度
void send_array_com( unsigned char *str, unsigned int length)
{
uint k= 0 ;
do
{
send_char_com(*(str + k));
k++;
}
while (k<length);
}
//显示函数 138译码器显示
void display()
{
char i;
// X_all=1234;
// D_all=5678;
led[0]=table[X_all/1000];
led[1]=table[X_all%1000/100];
led[2]=table[X_all%100/10];
led[3]=table[X_all%10];
led[4]=table[D_all/1000];
led[5]=table[D_all%1000/100];
led[6]=table[D_all%100/10];
led[7]=table[D_all%10];
for( i=0; i<8; i++) //实现8位动态扫描循环
{
P0 = led; //将字模送到P0口显示
switch(i)
{
case 0:HC138A0=0; HC138A1=0; HC138A2=0; break;
case 1:HC138A0=1; HC138A1=0; HC138A2=0; break;
case 2:HC138A0=0; HC138A1=1; HC138A2=0; break;
case 3:HC138A0=1; HC138A1=1; HC138A2=0; break;
case 4:HC138A0=0; HC138A1=0; HC138A2=1; break;
case 5:HC138A0=1; HC138A1=0; HC138A2=1; break;
case 6:HC138A0=0; HC138A1=1; HC138A2=1; break;
case 7:HC138A0=1; HC138A1=1; HC138A2=1; break;
}
delay(10);
}
}
//条件发送(按键闭合或收到主机指令,单片机像主机发送指令)
void send()
{
PS=1;
if(KEY1 ==0)
{
Delay_1ms(30); //30ms软件防抖
while(!KEY1);
M_RE=1;
M_DE=1; // 串口处于发送状态
send_array_com(led,8);
M_RE=0;
M_DE=0; //设置串口再次处于接收状态
}
/* if(flag=1) //单片机接受到主机上的指令,想主机发送数据。
{
flag=0;
M_RE=1;
M_DE=1; // 串口处于发送状态
send_array_com(led,8);
M_RE=0;
M_DE=0; //设置串口再次处于接收状态
}
*/
PS=0;
}
/*************主函数***************/
void main()
{
P0=table[0];
display();
D1=0; //对灯D1赋值,开始时为亮,当有外部中断,则灯灭。
delay(50);
coun(); //初始化
init_serialcomm(); //初始化串口
while(1)
{
if(m==300) // 1200采样时间1分钟,达到时间后停止采样 (300为15s)
{
EX0=0;
EX1=0;
m=0;
D_all=Num1;
X_all=Num2;
X_all-=D_all;
Num1=0;Num2=0;
EX0=1;
EX1=1;
}
send();
display();
}
}
/*************中断函数***************/
void int0() interrupt 0 using 1
{
EX0=0;
Num1++;
EX0=1;
D1=1;
}
void int1() interrupt 1 using 2
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
m++;
}
void timer0() interrupt 2 using 3
{
EX1=0;
Num2++;
EX1=1;
}
/*
//串口接收中断函数
void serial () interrupt 4 using 0
{
if (RI)
{
uchar temp;
RI = 0 ;
temp=SBUF;
flag=1;
if(temp='a')
flag=1;
}
} */
粗劣看一下这里就有一个不严谨的错误coun(); //初始化
init_serialcomm(); //初始化串口
程序中共用的寄存器应该用或与操作才不容易犯这种正确的错误。coun()中TMOD设置了定时器0为方式1而在init_serialcomm()设置波特率初始化时又把定时器0设置成了方式0.共用寄存器应该写成TMOD|=0X01;TMOD|=0X10形式就不会因为其他地方没有意识到而被粗心更改
两个函数共用TMOD,你把第二个中的改成TMOD|=0X20
两个函数共用TMOD,你把第二个中的改成TMOD|=0X20
恩,谢谢
这个不错,多谢小编