颜如晶语录:单片机和PC机之间的串行通信(追加200分帮你拿大奖)(1)

来源:百度文库 编辑:高校问答 时间:2024/05/02 17:44:44
麻烦大家帮我搞懂下面几个小问题 (,由于小弟时间紧,有更多奖励分,可分条答,每条400分)
80c51和pc 机通过串行通信的 电平转换用的MAX232
(1)单片机端的数据传输程序 汇编或者c51
(2)pc机端的vb或者vc编写的通信程序 最好是vb
(3) pc机 用的是com1 9针端口

如有不便 请发到小弟的邮箱kang068@126.com
谢谢拉

用Keil C51编程的例子,通讯规约用的是OMRON协议,简单解释一下:
每条命令或响应均以字符"@"开头,以0x2A0D结尾
起始字符@ 后面是你的规约定义的命令识别码,比方:0x03代表什么意思,把它的每一个16进制位用ASCII表示,发送,这里就是0x3033
然后是可能发送的数据
然后是校验码,就是从@开始的所有字节的异或结果然后用ASCII表示其中的单个16进制位,比如:计算结果是0x89,则FCS码是0x3839

其余的看注释吧,上位机用VB的过两天给你。

#include <REG51F.h>
#include <INTRINS.H>
#define uchar unsigned char
#define uint unsigned int
#define InNum 20 //一次收到的最大数据字节数
#define true 1
#define false 0

//函数声明
unsigned int checksum(uchar *p, uchar count);
bit init_com(void);
bit uploadstate(void);
void getstate(uchar index, uchar *p);
void doResp(void);
uchar getstatecount();

//全局变量
union //用公用体,命令与响应共用一段存储器,节省资源
{unsigned char In[InNum]; //输入数据数组
struct
{unsigned char s; //开始字节,必须以'@'开始,ASCII码为40H
unsigned int id; //识别码,两个字符的命令码
unsigned char para[8];//操作参数,依具体命令而变化,四个字符
unsigned int fcs; //两个字符的FCS码,即:帧检查序列
unsigned int end; //两个字符的终端码,即:”ד和”回车符“
}Command; //单片机发送命令给上位机
struct
{unsigned char s; //开始字节,必须以'@'开始,ASCII码为40H
unsigned int id; //识别码,两个字符的命令码
unsigned int finish;//结束码,两个字节
unsigned int end; //两个字符的终端码,即:”ד和”回车符“
}Response; //单片机发送命令给上位机时的上位机响应
//其余类似定义结构体

}Com;

bit cancle; //是否取消

//设定UART扩展功能变量
bit e_r; //收到完整命令
bit e_t; //发送响应数据尚未完毕
uchar uart_r_byte_num ;
uchar uart_r_buf;
uchar *uart_t;

/*****************************************************************************
功能:初始化串口设备(采用TIMER 2)
输入:无
输出:无
*****************************************************************************/
void init_serialcomm(void){
T2CON |= 0x34; //timer 2, 16-bit reload,timer 2 run,波特率发生器
SCON = 0x40; //SCON: serail mode 1, 10-bit UART,不允许接收数据
RCAP2H = 0xFF; //根据自己的晶振重新赋值
RCAP2L = 0xDF; //根据自己的晶振重新赋值
TR2=1; //定时器2启动
IE |= 0x90; //Enable Serial Interrupt
IP = 0x10; //只允许串口中断为最高优先级,其它为次优先级。
e_r=0;
e_t=0;
}

/*-----------------------------------------------------
主程序
-----------------------------------------------------*/
main()
{ bit ok;
init_serialcomm(); /*初始化串口*/
RI=0;
ES=1;

ok=uploadstate(); //例子函数,上传一个数据给PC

while(1)
{
if(_testbit_(e_r)) doResp();

}

}

/****************************************************************************
功能:串口中断服务函数,自动完成串口数据发送(自动发送数据包)和数据接收
输入:uart_t_byte_num, uart_t_buf[???] uart_busy
输出:uart1_r_flag,uart_r_buf uart_busy
*****************************************************************************/
void serial (void) interrupt 4 using 1
{

if(RI){
RI=0; //有新输入数据
uart_r_buf=SBUF; //缓存子串口1收到的数据,以便接收后续数据
if(!(e_r || e_t)) //既不处在命令状态,又不处在响应状态
{ //就可以接收下一条命令
if(uart_r_buf=='@') {Com.In[0]='@';uart_r_byte_num=1;return;}
if(uart_r_byte_num)// 接收字节数不为0,表明已经开始接收数据
{
Com.In[uart_r_byte_num]=uart_r_buf;
if(Com.In[uart_r_byte_num]==0x0D && Com.In[uart_r_byte_num - 1]==0x2A)//收到结束码(×,回车)
{e_r=1;}//设定收到Com完整命令字标志
uart_r_byte_num++;//记录收到的命令字字节个数
if(uart_r_byte_num>InNum)//收到数据个数要超过接收数组范围,重新开始
{e_r=0;uart_r_byte_num=0;}
}
}
}

if(TI)
{
TI=0;
if(e_t)
{ //如果子串口1有待发送的响应数据,则发送
SBUF=*uart_t; //将串口1发送指针所指数据发出
if(*uart_t==0x0D)
if(*(uart_t-1)==0x2A) e_t=0;//如果发送的是最后一个字符
uart_t++; //串口1发送指针加一,指向下一个待发数据
}
}
}

/*********************
函数名: uploadstate
描 述: 上传状态
参 数: 无
返回值: 成功为1,否则为0
**********************/
bit uploadstate(void)
{
uchar i,j;
i=getstatecount();
if(i<=0) return(1);
if(init_com()==0) return(0);//负责和主机握手,例如发送0x5A,收到0xA5
Com.Command.s='@';
Com.Command.id=0x3033; //识别码,两个字符的命令码,通讯规约自己定义
Com.Command.end=0x2A0D;
for(j=0;j<i;j++)
{
getstate(j,Com.Command.para);
Com.Command.fcs=checksum(&Com.Command,10); //两个字符的FCS码,即:帧检查序列
uart_t=&Com.Command;
EA=1;
TI=1;

e_t=1;
while(e_t);
do
{
e_r=0;
while(!e_r) {if(cancle) return(0);}
}
while(Com.Response.id !=0x3330);
if(Com.Response.finish !=0x3030) j--;
}
return(1);
}

/*********延时Count个us**************/
void delayus(uchar Count)
{
while(Count--);
}

/*********延时Count个ms**************/
void delay(uchar Count)
{
uchar i=4;
while(Count--)
{
while(i--)
delayus(250);
}
}

/*********************
函数名: init_com
描 述: 与上位机握手,持续发送0x5A,直到收到0xA5
参 数: 无
返回值: 成功为1,否则为0
**********************/
bit init_com(void)
{
RI=0;
while(1)
{
EA=0;
SBUF=0x5A;
delay(5);
if(_testbit_(RI) && SBUF==0xA5) {TI=0;return(1);}
if(cancle) return(0);
}
}

/*********************
函数名: checksum
描 述: 生成FCS码
参 数: p:要计算FCS的数组,要计算多少个元素
返回值: FCS码,整形
**********************/
unsigned int checksum(uchar *p, uchar count)
{
uchar i,OMRON;
union
{
unsigned int j;
unsigned char l[2];
}k;

OMRON=0;
for(i=0;i<count;i++,p++) OMRON = OMRON ^ (*p);
i=OMRON & 0x0f;
if(i<10)
i += 0x30;
else
i +=0x37;
k.l[1]=i;
i=OMRON >> 4;
if(i<10)
i += 0x30;
else
i +=0x37;
k.l[0]=i;
return(k.j);
}

//以下为试验函数--------------------------------------------------

//取得状态数目
uchar getstatecount()
{
return(1);
}

//取得指定状态
void getstate(uchar index, uchar *p)
{
*p=0x01;
*(p+1)=0x02;
*(p+2)=0x03;
*(p+3)=0x04;
*(p+4)=0x05;
*(p+5)=0x06;
*(p+6)=0x07;
}

//响应函数
void doResp(void)
{
return;
}

PC机及单片机通讯技术
http://www.pp51.com/BOOK/05.htm
参考一下这里,很全面的

http://www.51c51.net/article/show.asp?id=617

你要的东西在MSDN里边有

我有但是你怎么把分给我呢?