找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 756|回复: 4
打印 上一主题 下一主题
收起左侧

单片机之间数据传输问题,如何传输大于一个字节的量?

[复制链接]
跳转到指定楼层
楼主
ID:849316 发表于 2022-4-13 11:22 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在第一个AT89C52单片机上,通过速度公式v=s/t计算出速度V。通过定义发送函数和接收函数实现速度信息V的传递并在第二个单片机中运用第一个单片机计算出的速度进行运算推导时间然后进行倒计时。通过对程序的逐部分检验发现主要问题是SBUF传递的速度数值V在0-255可以准确传递但是一旦超过一个字节范围即0-255就会失真。
查阅书籍发现大多是利用for循环依次发送定义数组内已知的数。那么如何定义发送和接收函数才能实现依次发送时间不定的速度量的个位、十位、百位和小数点位哪?
具体程序如下:
发送程序:
/**************************************************************************************                                                  *
*按下K1按键  开始计时
*按下K2按键  计时结束计算速度                                                                                 
***************************************************************************************/
#include "reg52.h"             //此文件中定义了单片机的一些特殊功能寄存器
#include<intrins.h>             //左右移函数,头文件
#include<absacc.h>           //访问绝对地址头文件
sbit k1=P1^0;     //按键1开始计时
sbit k2=P1^1;     //按键2终止计时开始计算速度
sbit dian=P0^7;                  //小数点
unsigned char xiao=0,ge=0,shi=0,bai=0;        //定义数码管显示的个位和十位   
unsigned int num=0,sec=0,m=0,v=0,t=0,t1=0,t2=0,t3=0;//定义ms、s、时间总数和速度
unsigned char code table[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//数码管段控口
/*******************************************************************************
* 函 数 名         : delay
* 函数功能           : 延时函数
*******************************************************************************/
void delay(unsigned int i)            
{
    while(i--);               // 去抖延时
}
/*******************************************************************************
* 函 数 名         : Timer0Init
* 函数功能           : 定时器0初始化
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void Timer0Init(void)        //10微秒@12.000MHz
{
    TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。
    TL0 = (65536-10000)%256;        //设置定时初值
    TH0 = (65536-10000)/256;        //设置定时初值
    ET0=1;//打开定时器0中断允许
    EA=1;//打开总中断
    TR0=1;//打开定时器   
}
/*******************************************************************************
* 函 数 名         : display
* 函数功能           : 速度显示函数
*******************************************************************************/
/******速度显示函数******/
void display()              //列车一般情况下列车的平均速度为300km/h约等于83m/s
{
ge=v%10;                  //求个位
bai=v/100;                  //求百位
shi=(v-100*bai)/10;      //求十位
xiao=(v-100*bai-10*shi-ge)/0.1;   //求小数位
P2=0xf7;                  //选择数码管1,输入位选信号
P0=table[xiao];              //数码管段选信号,显示小数位数值
delay(15);
P2=0xfb;                  //选择数码管2,输入位选信号
P0=table[ge];              //数码管段选信号,显示个位数值
dian=1;                  //小数点点亮
delay(15);
P2=0xfd;                  //选择数码管3,输入位选信号
P0=table[shi];              //数码管段选信号,显示十位数值
delay(15);
P2=0xfe;                  //选择数码管4,输入位选信号
P0=table[bai];              //数码管段选信号,显示百位数值
delay(15);
}
/*******************************************************************************
* 函 数 名         : keypros
* 函数功能           : 按键处理函数,判断按键是否按下并
*******************************************************************************/
void keypros()
    {
    if(k1==0)          //检测按键K1是否按下
    {   
    delay(1000);   //消除抖动 一般大约1ms
    if(k1==0)     //再次判断按键是否按下
    {
    num++;
    TL0 = (65536-1000)%256;        //设置定时初值
    TH0 = (65536-1000)/256;        //设置定时初值
    if(num==1000)                //时间到达1s
    {
    num=0;                        //重新从1ms开始计时
    sec++;                        //累计1S
    }
    }
    }
    }
    /*****发送*********/
void Send ()
{    unsigned char dat ;
    dat=v;           //速度中间量
    SBUF=dat;       //发速度
    while(TI==0); //串行通信口中断
    TI=0;          //手动赋初值
}
/*******************************************************************************
* 函 数 名       : main
* 函数功能         : 主函数
*******************************************************************************/
void main()
{   
    Timer0Init();  //定时器0初始化
    TMOD=0x20;       //定时器1工作于方式2
    SCON=0x50;       //定时器串口工作方式1允许接收
    PCON=0x00;       //波特率9600
    TH1=0XFD;       //根据规定给定时器T1赋值
    TL1=0XFD;       //根据规定给定时器T1赋值
    TR1=1;           //启动定时器T1
    while(1)
    {   
    keypros();  //按键处理函数   
    }        
}
/*******************************************************************************
* 函 数 名         : void Timer0() interrupt 1
* 函数功能           : 定时器0中断函数
*******************************************************************************/
void Timer0() interrupt 1
{
    TL0 = (65536-10000)%256;        //设置定时初值
    TH0 = (65536-10000)/256;        //设置定时初值
    if(k2==0)          //检测按键K2是否按下
    {   
    delay(1000);   //消除抖动 一般大约1ms
    if(k2==0)     //再次判断按键是否按下
    {
    v=5000/(1000*sec+num)*3.6;             //速度公式求列车速度单位为km/h
    while(1)
    {
    display();    //显示函数
    Send ();
    }
    }
    }   
    while(!k2);     //检测按键是否松开
}
接收程序:
/**************************************************************************************                                                  *
*按下K1按键  开始计时
*按下K2按键  计时结束计算速度                                                                                 
***************************************************************************************/
#include "reg52.h"             //此文件中定义了单片机的一些特殊功能寄存器
#include<intrins.h>             //左右移函数,头文件
#include<absacc.h>           //访问绝对地址头文件
sbit k3=P3^5;     //抬杆
sbit dian=P0^7;                  //小数点
unsigned char xiao=0,ge=0,shi=0,bai=0,count=0;        //定义数码管显示的个位和十位     
unsigned int v=0,t=0,t1=0,t2=0,t3=0,t4=0;//定义ms、s、时间总数和速度
unsigned char code table[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//数码管段控口
/*******************************************************************************
* 函 数 名         : Init
* 函数功能           : 初值函数
*******************************************************************************/
/******初值函数******/
void Init(void)
{
        TMOD=0x01;
        TH0=(65536-10000)/256;
        TL0=(65536-10000)%256;
        TR0=1;
        ET0=1;
        EA=1;
}
/*******************************************************************************
* 函 数 名         : timer
* 函数功能           : 中断函数
*******************************************************************************/
/******中断函数******/
void timer0(void) interrupt 1
{   
        TMOD=0x01;
        TH0=(65536-50000)/256;
        TL0=(65536-50000)%256;
        TR0=1;
        ET0=1;
        EA=1;
           count++;
        if(count>19)
        {
            count=0;
            t3--;      
         }      
}
/*******************************************************************************
* 函 数 名         : delay
* 函数功能           : 延时函数
*******************************************************************************/
/******延时函数******/
void delay(unsigned int i)            
{
    while(i--);               // 延时
}
/*****时间显示函数*********/
void display()
        {   
        ge=t3%10;                  //求个位
        bai=t3/100;                  //求百位
        shi=(t3-100*bai)/10;          //求十位
        xiao=(t3-100*bai-10*shi-ge)/0.1;   //求小数位
        P2=0xf7;                  //选择数码管1,输入位选信号
        P0=table[xiao];              //数码管段选信号,显示小数位数值
        delay(15);
        P2=0xfb;                  //选择数码管2,输入位选信号
        P0=table[ge];              //数码管段选信号,显示个位数值
        dian=1;                  //小数点点亮
        delay(15);
        P2=0xfd;                  //选择数码管3,输入位选信号
        P0=table[shi];              //数码管段选信号,显示十位数值
        delay(15);
        P2=0xfe;                  //选择数码管4,输入位选信号
        P0=table[bai];              //数码管段选信号,显示百位数值
        delay(15);
        }

/*******************************************************************************
* 函 数 名         : Receive
* 函数功能           : 接收函数
*******************************************************************************/
unsigned char Receive(void)
{
    unsigned char dat;
    while(RI==0);
    RI=0;
    dat=SBUF;
    return dat;
}
   
/*******************************************************************************
* 函 数 名       : main
* 函数功能         : 主函数
*******************************************************************************/
void main()
{   
    TMOD=0X20;       //定时器1工作于方式2
    SCON=0X50;       //定时器串口工作方式1允许接收
    PCON=0x00;       //波特率9600
    TH1=0XFD;       //根据规定给定时器T1赋值
    TL1=0XFD;       //根据规定给定时器T1赋值
    TR1=1;           //启动定时器T1
    REN=1;           //允许接收
    v=Receive();
    t=5.5*3600/v;                        //计算到达安全位置时间,单位h.小时到微妙t1=t*60*60*1000*1000;    t2=t1/1000000;    //多少秒
    t3=t+10;                        //在原定实践基础上处于安全考虑延长10s后所需要的时间
    while(1)                        
    {    k3=0;                    //抬杆落下
    EA=1;                        //开中断
    Init();                        //赋初值
    while(t3!=0)                //计时不为0
    {
        display();                //显示函数
    }
    while(t3==0)                //计时为0
    {
    k3=1;                       //抬杆抬起
    while(1);                   //终止
    }
    }
   
}
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:538157 发表于 2022-4-13 16:57 | 只看该作者
本帖最后由 xu2509674896 于 2022-4-13 17:01 编辑

首先编写一个发送数组的函数,数组长度为4,将计算得到的V(根据信息推测为浮点型)转换为IEEE754格式(原理和如何转换烦请百度),发送存有IEEE格式的数组,2号单片机将IEEE754格式的数组转化为浮点数
回复

使用道具 举报

板凳
ID:123289 发表于 2022-4-13 17:28 | 只看该作者
架构不合理,教你一个方式:
不要直接发送!
1、建议一个发送缓冲区
2、需要发送数据时,就将要发送的内容依次写入这个区内,就当是发送了。
3、单独写个发送程序,依序从发送缓冲区中取数据发送。
细节部分不在此介绍,接收也不在此介绍。
理由,主程序给出数据是瞬间的事,而发送过程则是一个字节、一个字节的发出的(接收也一样)。
这样做,主程序在给出数据时,不用一个个等,是否完成了一个字节发送?而是一下写入缓冲区,再由发送程序去处理发送的事。而发送程序可以用中断去处理,中断一次发一个字节,也不用等,只要记住需要发送的字节在何处取就可以了。

要点:收发的双方要有个协议,解决:
1、双方如果握手?(多机确认,这里可省)
2、丢失数据后如何补救?(涉及数据的完整性、有效性、正确性)
3、数据的开始与结束?(涉及如何组装数据)
4、数据的结构?(涉及如何组装数据)
5、……
回复

使用道具 举报

地板
ID:121859 发表于 2022-4-13 19:37 | 只看该作者
大于一个字节的量传输,可以采用多字节传输,当然这就要建立双方的协议了。

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

5#
ID:883242 发表于 2022-4-13 19:47 | 只看该作者
单片机传单片机,因为双方实时性都很好,可以用定时间隔比如1ms作为数据帧分隔标志,总线空闲1ms来的第一个字节就是帧头。

单片机传上位机,因为PC实时性不好,转成ASCII字符传输,用特殊字符表达帧头帧尾。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表