补充:

程序优化

为避免普通发送和中断发送造成冲突(造成死机,复位重启),printf修改为中断发送

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

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

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

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

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

大多数人是不是还是这样

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]);
}

直接说弊端,举个例子

void main()
{
InitUART(9600);
InitTimer0();
while(1)
{
for(i=0;i<130;i++)
{
UartSend(Data[i]);
}
DataConfig();//采集数据
DataSendMethod();//接收串口命令
......
}
}

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

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

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

/**
* @brief 串口发送函数中断函数
* @param
* @param None
* @param None
* @retval None
* @example
**/
void UartSendTI(unsigned char *value,int DataLen)
{
UsartSendData = value;
UsartSendDataCnt = DataLen;
TI = 1;
}

  

void UARTInterrupt(void) interrupt 4
{
if(TI)
{
TI = 0;
if(UsartSendDataCnt>0)
{
SBUF = *UsartSendData++;
UsartSendDataCnt--;
}
else
{
TI = 0;
}
}
}

 

发送数据的时候直接

UartSendTI(AD0123Table,21);

AD0123Table是一个数组

void main()
{
InitUART();
InitTimer0();
while()
{
UartSendTI(AD0123Table,); DataConfig();//采集数据 }
}

这样的话这个函数

UartSendTI(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里面....

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

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
{
rbRead(&Uart1rb, &Usart1SendDat, );//读取一个数据
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 = ;
if(NULL == buf)
{
printf("ERROR: gizPutData buf is empty \n");
return -;
}
count = rbWrite(rb, buf, len);//存入数据
if(count != len)
{
printf("ERROR: Failed to rbWrite \n");
return -;
}
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;
char Data_Table[];
}ResolverfData; typedef union ResolverLong//STM32为小端模式
{
long Data;
char Data_Table[];
}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[] = 0x00;
ResolverData.Data_Table[] = 0x80;
ResolverData.Data_Table[] = 0x5C;
ResolverData.Data_Table[] = 0x43; printf("%f\r\n",ResolverData.Data);

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

byte[] FloatDataMore = new byte[];
FloatDataMore[] = 0x00;
FloatDataMore[] = 0x80;
FloatDataMore[] = 0x5C;
FloatDataMore[] = 0X43; float f = BitConverter.ToSingle(FloatDataMore, );//转换 f = 220.5

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

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

就像上面的220.5 用stm32解析数据后存储的情况 0x00 0x80 0x5C 0x43 

0x00是不是存在了数组的地位上哈,,,0x43存在了数组的高位上...

看一下51 的

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

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

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

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

/**
* @brief 计算CRC
* @param *modbusdata:数据指针
* @param length:数据长度
* @param
* @retval 计算的CRC值
* @example
**/
unsigned int crc16_modbus(unsigned char *modbusdata, char length)
{
char i, j;
unsigned int crc = 0xffff;//有的用ffff有的用0
for (i = ; i < length; i++)
{
crc ^= modbusdata[i];
for (j = ; j < ; j++)
{
if ((crc & 0x01) == )
{
crc = (crc >> ) ^ 0xa001;
}
else
{
crc >>= ;
}
}
} return crc;
}
    crc = crc16_modbus(AD0123Table,);

    AD0123Table[] = crc&0xff;
AD0123Table[] = (crc>>)&0xff; UartSendTI(AD0123Table,);

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

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

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

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

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

    上一篇链接 http://www.cnblogs.com/yangfengwu/p/8628219.html 先说明一点这种方式,不光对于单片机类的,,对于上位机接收数据同样适用----不骗人的,自己 ...

  2. C++/java之间的Socket通信大小端注意事项

    在一个物联往项目中,需要java云平台与一个客户端做socket定制协议的通信:然而在第一次测试时,并没有按照预想的那样完成解析.查找资料以后是因为客户端的数据读取方式为小端模式,而java默认采用大 ...

  3. MM32F0020 UART1中断接收和UART1中断发送

    目录: 1.MM32F0020简介 2.初始化MM32F0020 UART1和NVIC中断 3.编写MM32F0020 UART1使能中断发送函数 4.编写MM32F0020 UART1中断接收和中断 ...

  4. MM32F0140 UART1中断接收和UART1中断发送

    目录: 1.MM32F0140简介 2.初始化MM32F0140 UART1和NVIC中断 3.编写MM32F0140 UART1使能中断发送函数 4.编写MM32F0140 UART1中断接收和中断 ...

  5. 关于STM32空闲中断

    有一次做一个东西,为了尽量不占用CPU的处理数据时间,所以就使用DMA接收串口的数据,但是呢问题来了.,,,,,怎么样才能确定接收到了一条完整的数据了,,我们都知道只要打开DMA 那家伙就不停的把接收 ...

  6. MM32F0140 UART1空闲中断接收

    目录: 1.MM32F0140简介 2.初始化MM32F0140 UART1空闲中断和NVIC中断 3.编写MM32F0140 UART1中断接收和空闲中断函数 4.编写MM32F0140 UART1 ...

  7. MM32F0020 UART1空闲中断接收

    目录: 1.MM32F0020简介 2.初始化MM32F0020 UART1空闲中断和NVIC中断 3.编写MM32F0020 UART1中断接收和空闲中断函数 4.编写MM32F0020 UART1 ...

  8. 51单片机-PC数据传输 温度 距离 监控系统设计

    >_<:功能概述: 通过串口PC和单片机通信,可以询问单片机测得的温度,可以询问声呐测距的测量距离,同时把测量温度显示在数码管上. >_<:PC部分 这里com.cpp和com ...

  9. ucos-iii串口用信号量及环形队列中断发送,用内建消息队列中断接收

    串口发送部分代码: //通过信号量的方法发送数据 void usart1SendData(CPU_INT08U ch) { OS_ERR err; CPU_INT08U isTheFirstCh; O ...

随机推荐

  1. DRF序列化/反序列化

    反序列化(不推荐版):两个字段 一个为正序准备,一个为反序准备重写create update方法 1. 确定数据结构: 自己定义key book_obj = { "title": ...

  2. 如何使用活字格快速搭建Bug管理系统?

    Bug管理系统是指一种用于添加Bug.修复Bug.测试Bug.删除Bug的一套完整的Bug管理系统. 完整的Bug管理过程包含: 1.测试人员利用Bug管理系统提交发现的bug. 2.测试人员把bug ...

  3. CentOS7+ApacheServer2.4+MariaDB10.0+PHP7.0+禅道项目管理软件8.0环境部署

    CentOS7+ApacheServer2.4+MariaDB10.0+PHP7.0+禅道项目管理软件8.0环境部署 by:授客 QQ:1033553122 目录 一. 二. 三. 四. 五. 六. ...

  4. 安卓测试【一】android sdk环境变量配置

    移动应用自动化测试的配置,先于官网下载Android SDK,然后配置环境变量. 配置android sdk环境变量 1.  新建ANDROID_HOME环境变量,变量值为SDK解压的路径 2. 追加 ...

  5. unityShader CGINCLUDE关键字

    unityshader中经常见到CGPROGRAM,除此之外还有一个CGINCLUDE关键字. 二个关键字都是用ENDCG来结束,但是用法完全不一样. CGINCLUDE和ENDCG内可以插入一些sh ...

  6. 成为Java顶尖程序员,先过了下面问题!

    一.数据结构与算法基础 说一下几种常见的排序算法和分别的复杂度. 用Java写一个冒泡排序算法 描述一下链式存储结构. 如何遍历一棵二叉树? 倒排一个LinkedList. 用Java写一个递归遍历目 ...

  7. zabbix系列之九——安装后配置四web监控

    1web监控 描述 详细 备注 概要 1)      需要定义 web 场景(包括一个或多个 HTTP请求),zabbix服务器根据预定义的命令周期性的执行这些步骤. 2)      Web 场景和 ...

  8. 单点登录SSO的实现原理 (转)

    单点登录SSO(Single Sign On)说得简单点就是在一个多系统共存的环境下,用户在一处登录后,就不用在其他系统中登录,也就是用户的一次登录能得到其他所有系统的信任.单点登录在大型网站里使用得 ...

  9. C# 泛型约束 xxx<T> Where T:约束(一)

    泛型约束 代码举例 发现我们游戏的代码中,主程写了很多类似这样的代码: public static T CreateObject<T>(out int objectId) where T ...

  10. 【转】Spring学习---SpringIOC容器的初始化过程

    [原文]https://www.toutiao.com/i6594400249429623304/ SpringIOC容器的初始化过程 简单来说,IoC容器的初始化是由refresh()方法来启动的, ...