1-关于单片机通信数据传输(中断发送,大小端,IEEE754浮点型格式,共用体,空闲中断,环形队列)

今天登录简书看到有很多关注的所以就把自己在博客园写的文章都复制粘贴过来

写这篇文章的目的呢,如题目所言,我承认自己是一个程序猿.....应该说很多很多学单片机的对于...先不说别的了,,无论是学51的还是32的,,,先问一下大家用串口发送数据的时候是怎么发的???如果发整型的数据是怎么发的??如果发浮点型的是怎么发的????再问大家串口接收数据是怎么接收的????亲们有没有想过自已用的方法是不是最好最好的方法了,反正我认为我自己现在用的方法应该是很好的了,,不说最好,因为我知道我还能在现在的基础上稍微的修改让它变为更好....只是感觉无所谓了,因为现在所用的方法对于99.9999%的项目都适用....

好像自己在吹牛一样,,,,,其实写这篇文章呢,,,也早就想写了,因为感觉好东西应该拿出来分享一下,希望亲们能派的上用场

先给大家源码一个51的一个32的

链接:https://pan.baidu.com/s/1ZFcJYEWwMCXZYyRUVjknKQ 密码:i4pl

先看第一个问题,,,,大家用串口发送数据的时候是怎么发的???

大多数人是不是还是这样


1

2

3

4

5

6

7

8

9

10

11

12

13

14

for(i=0;i<30;i++)

{

    UartSend(Data[i]);

}


void UartSend(unsigned char value)

{

    ES=0; //关闭串口中断--使用Printf 需要屏蔽

    TI=0; //清发送完毕中断请求标志位  

    SBUF=value; //发送 

    while(TI==0); //等待发送完毕  

    TI=0; //清发送完毕中断请求标志位 --使用Printf 需要屏蔽  

    ES=1; //允许串口中断  --使用Printf 需要屏蔽

}

上面是51的,只是打比方哈

 就是说

for(i=0;i<30;i++)

{

UartSend(Data[i]);

}

直接说弊端,举个例子


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

void main()

{

    InitUART(9600);

    InitTimer0();

    while(1)

    {

        for(i=0;i<130;i++)

        {

            UartSend(Data[i]);

        }

        DataConfig();//采集数据

                DataSendMethod();//接收串口命令

        ......

         }

}

每次都要发130个数据,,是不是每次循环要等着发完上面的130个数据才执行下面的函数,,,这样话就不能及时的执行后面的函数,,,,刚想起来有没有人经常在主循环里面加延时的?????水平不高的人,,才会经常在主循环里面加延时

那应该怎么发....用中断发

先看最普通的,用51写的一个

1

2

3

4

5

6

7

8

9

10

11

12

13

14

/**

* @brief  串口发送函数中断函数

* @param 

* @param  None

* @param  None

* @retval None

* @example

**/

void UartSendTI(unsigned char *value,int DataLen)

{

    UsartSendData = value;

    UsartSendDataCnt = DataLen;

    TI = 1;

}


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

void UARTInterrupt(void) interrupt 4

{

    if(TI)

    {

        TI = 0;

        if(UsartSendDataCnt>0)

        {

                  SBUF = *UsartSendData++;

          UsartSendDataCnt--;

                }

        else

        {

                  TI = 0;

                }

        }

}

发送数据的时候直接

UartSendTI(AD0123Table,21);

AD0123Table是一个数组

1

2

3

4

5

6

7

8

9

10

11

12

void main()

{

    InitUART(9600);

    InitTimer0();

    while(1)

    {

        UartSendTI(AD0123Table,21);


        DataConfig();//采集数据


       }

}

这样的话这个函数

1UartSendTI(AD0123Table,21);
只是告诉串口去发送数据,并不会占用主循环多少时间,然后就立马执行下面的函数去了,其实现在的情况就是不停的进中断发送数据
又不停的从中断里面出来执行主循环,,,这种方式想一想是不是要比以前那样好多了???

现在再升级一下
大家有没有看过我这篇文章
http://www.cnblogs.com/yangfengwu/p/6822984.html  关于环形队列的

看到那个环形队列的程序是不是有头疼的????如果谁读起来吃力,说明底子还是不行哈,,,
指针理解的怎么样???结构体会不会,,结构体指针呢????不会没有啥法子说明自己懒,也有可能没有遇到好老师....突然想起来一句话
会的多的人写程序又快有好,也很轻松,因为他会复制粘贴,,,,有些人会问那不会的也能啊!!问一句,不会的,你敢复制粘贴不,
即使复制粘贴了,你知道怎么用不????即使能用了稳定性上能得到保证不????

我现在往数组里面存数据

然后我再往里面存,,对了存数据是用的操作环形队列的函数哈  int32_t rbWrite(rb_t *rb, const void *data, size_t count)


 我又存了两个,,如果存满了还存,就会报错,,所以咱呢先取两个再存,,取数据也是用的环形队列的函数




然后咱们再存两个吧!!

具体是如何实现的就看这两个吧

函数在32的工程里面,51享受不起.....内存堪忧


我发送数据的时候就是直接往这个数组里面存数据,串口从这个数组里面取数据然后发出去(当然这个是在程序中设置的)

那个数组就是一直在转圈圈......

曾经就有一个问题就是利用环形队列解决的

http://www.cnblogs.com/yangfengwu/p/6921832.html

简单来说就是把接收到的数据写到Flash里面....但是呢单片机的内存有限,不能够一次性接收到所有的数据......所以我就

利用环形队列..一边串口接收着往环形队列里面写数据,一边从环形队列里面读出数据写到Flash里面....


现在看如何利用环形队列发送串口数据

1

2

3

4

5

6

7

8

9

10

11

12

void rbCreate(rb_t* rb,u8 *Buff,uint32_t BuffLen)//创建或者说初始化环形缓冲区

{

    if(NULL == rb)

    {

        printf("ERROR: input rb is NULL\n");

        return;

    }

    rb->rbCapacity = BuffLen;//数组的大小

    rb->rbBuff = Buff;//数组的地址

    rb->rbHead = rb->rbBuff;//头指向数组首地址

    rb->rbTail = rb->rbBuff;//尾指向数组首地址

}

先看发送,这是在中断里面,就是如果数组里面有数据就一个一个取出来发出去

这是串口1 的,我定义了三个Uart1rb  Uart2rb  Uart3rb  分别操作  Usart1SendBuff    Usart2SendBuff    Usart3SendBuff  这三个数组



if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)

  {

    if(rbCanRead(&Uart1rb)>0)//如果环形队列里面的数据个数大于0    {

      rbRead(&Uart1rb, &Usart1SendDat,1);//读取一个数据USART_SendData(USART1, Usart1SendDat);//发送    }

    else    {

      //发送字节结束      USART_ClearITPendingBit(USART1,USART_IT_TXE);

      USART_ITConfig(USART1, USART_IT_TXE, DISABLE);

      USART_ITConfig(USART1, USART_IT_TC, ENABLE);

    }

  }


 现在看怎么存,应该说怎么控制串口发送数据


int32_t PutData(rb_t *rb ,USART_TypeDef* USARTx, uint8_t *buf, uint32_t len)

{

    int32_t count =0;

    if(NULL == buf)

    {

        printf("ERROR: gizPutData buf is empty \n");

        return-1;

    }

    count = rbWrite(rb, buf, len);//存入数据if(count != len)

    {

        printf("ERROR: Failed to rbWrite \n");

        return-1;

    }

    USART_ITConfig(USARTx, USART_IT_TXE, ENABLE);//然后控制打开哪一个中断return count;

}

发送数据的时候直接往里面丢数据就可以了

PutData(rb_t *rb ,USART_TypeDef* USARTx, uint8_t *buf, uint32_t len)

再高级一点,加上DMA,用DMA就不能用环形队列了,其实下面大神介绍的用内存分配的方式,实质就是用链表,但是呢!我没想明白把数据放进

链表然后设置一下DMA和直接用数组的方式设置一下DMA有多大区别,.....或许我还是没有明白那位大神的用意......所以我就还是用的现在

的环形队列的方式.....

可以看一下这位大神的介绍

https://wenku.baidu.com/view/c2b959f0caaedd3383c4d3d7.html


现在先问一下,如果让大家传输一个220.5的数据给上位机,大家如何传输??假设不加任何的标志校验什么的

我的话


看一下

typedef union Resolverf//STM32为小端模式{

    float Data;

    charData_Table[4];

}ResolverfData;

typedef union ResolverLong//STM32为小端模式{

    long Data;

    charData_Table[4];

}ResolverLongData;

DATAGATHER_C_ ResolverfData ResolverData;//解析单精度浮点型数据

DATAGATHER_C_ ResolverLongData ResolverLongDat;//解析整形

实际上220.5 用16进制表示就是 43 5C  80  00  高位在前

其实现在所有的仪器仪表的通信都是走的这种

链接:https://pan.baidu.com/s/1he-dK4_FUh9hXZBa9dpKwg 密码:2f9x


如果是整形

就用


用共用体直接就可以实现两边的转换,


ResolverData.Data_Table[0] =0x00;

        ResolverData.Data_Table[1] =0x80;

        ResolverData.Data_Table[2] =0x5C;

        ResolverData.Data_Table[3] =0x43;



        printf("%f\r\n",ResolverData.Data);


如果用上位机列如C#的,一个函数就搞定

byte[] FloatDataMore =newbyte[4];

FloatDataMore[0] =0x00;

FloatDataMore[1] =0x80;

FloatDataMore[2] =0x5C;

FloatDataMore[3] =0X43;floatf = BitConverter.ToSingle(FloatDataMore,0);//转换f =220.5

所以传输数据还是按照规范来


大家可以用51去试一试会发现和32的正好相反

0x43  高位存在了数组的低位上,,   0x00 存在了数组的高位上

 其实就是在说数据存储的时候数据的高位存在了低地址,数据的低位存在了高地址,,,就是大端模式


一般我发送数据会在最后加CRC16校验   

/**

* @brief  计算CRC

* @param  *modbusdata:数据指针

* @param  length:数据长度

* @param 

* @retval 计算的CRC值

* @example

**/unsigned intcrc16_modbus(unsignedchar*modbusdata,char length)

{

    char i, j;

    unsigned intcrc =0xffff;//有的用ffff有的用0for(i =0; i < length; i++)

    {

        crc ^= modbusdata[i];

        for(j =0; j <8; j++)

        {

                if((crc &0x01) ==1)

                {

                        crc = (crc >>1) ^0xa001;

                }

                else                {

                        crc >>=1;

                }

        }

    }


    return crc;

}


crc = crc16_modbus(AD0123Table,19);


    AD0123Table[19] = crc&0xff;

    AD0123Table[20] = (crc>>8)&0xff;


  UartSendTI(AD0123Table,21);


现在看接收.....算了明天再写吧,感觉这些够消化的了....................

程序里面所有的函数都封装好了,关键是自己亲自去尝试

下一篇链接http://www.cnblogs.com/yangfengwu/p/8912072.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容

  • 姓名:周崇杰 学号:16140120059 专业:机械设计制造及其自动化 转载自:http://blog.csd...
    CJbaby阅读 3,470评论 0 3
  • 1.ios高性能编程 (1).内层 最小的内层平均值和峰值(2).耗电量 高效的算法和数据结构(3).初始化时...
    欧辰_OSR阅读 29,289评论 8 265
  • 转眼间天亮了...... 然后就想起了一个朋友QQ的个性签名:年轻人总是要为一些自己认为有意义的事情而废寝忘食,通...
    杨奉武阅读 10,662评论 0 4
  • 我是一位跑者中,最不值得一提的小咖。没体验过全马,甚至半马。我只是想把自己每天坚持跑步,40天跑够200公里的心得...
    婉遇阅读 418评论 0 1
  • 体验、生活用来发现美、工作是为了实现感觉。 精进、感受经营幸福的过程、享受幸福生活、
    冯祥林阅读 98评论 0 0