精华内容
下载资源
问答
  • 串口发送数据

    千次阅读 2019-05-16 14:32:00
    关于串口发送数据,自己以前呢是这样 void Usart_Out_Char(unsigned char *c,uint32_t cnt){ while(cnt--) { USART_SendData(USART1, *c++); while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET ); }} ...

    关于串口发送数据,自己以前呢是这样

    void Usart_Out_Char(unsigned char *c,uint32_t cnt)
    {
    while(cnt--)
    {
    USART_SendData(USART1, *c++);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET );
    }
    }

    下面的调用方式

    uint8_t aaa[1024]={1,2,3,42,0};

    int main(void)
    {
    NVIC_Configuration();
    Led_Gpio_Init();
    Timer2_Config();
    uart_init(115200); //串口初始化为115200while(1)
    {
    Usart_Out_Char(aaa,1024);
    delay_ms(1000);
    PFout(6) = ~PFout(6);
    }
    }

    当发送数据的时候,会一直在调用此函数的地方等着,,,,,,直至发送完所有的数据,要知道用串口中断发送数据要比这样发送快的多.......瞎耽误时间

    假设现在我用中断发送

    void UsartOutChar(unsigned char *Buff,uint32_t cnt)
    {
    dat = Buff;//把发送地址给dat
    BuffCnt = cnt;//记录发送的个数
    USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//打开发送中断
    }

     

    void USART1_IRQHandler(void) //串口1中断服务程序
    {
    u8 Res;

    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
    {
    Res =USART_ReceiveData(USART1); //读取接收到的数据
    }
    if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)//发送中断
    {
    if(BuffCnt--)
    {
    USART_SendData(USART1,*dat);//发送数据
    dat++;
    }
    else
    {
    //发送字节结束
    USART_ClearITPendingBit(USART1,USART_IT_TXE);
    USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
    USART_ITConfig(USART1, USART_IT_TC, ENABLE);
    }
    }
    //发送完成
    if (USART_GetITStatus(USART1, USART_IT_TC) != RESET)
    {
    USART_ClearITPendingBit(USART1,USART_IT_TC);
    USART_ITConfig(USART1, USART_IT_TC, DISABLE);
    }
    }

     

    uint8_t aaa[1024]={1,2,3,42,0};

    int main(void)
    {
    NVIC_Configuration();
    Led_Gpio_Init();
    Timer2_Config();
    uart_init(115200); //串口初始化为115200while(1)
    {
    UsartOutChar(aaa,10);
    delay_ms(10);
    }
    }

     

    加一个缓冲区---假设是下面这样子,中断发送的数据从这个缓冲区里面取

    然后呢,接着又填入了

    接着

    假设我又想添加数据,可是呢后面空的那一块数据空间不够了......要是能把数组的尾和头联系起来就好啦......

    假设加满了,,,如果能自动的加到前面就好啦.....

     

    今天先这样...太晚啦..现在最大的愿望什么时候能安心睡个早觉..再这样下去真担心会挂了......有空再详加..

    下面是实现程序--实现程序是自己想学Esp8266连接机智云的时候无意中看到的,,,,,记得 天鲁哥 曾经说过环形队列实现的很巧妙,,,改天有空再研究下当初天鲁哥给的程序

     往里面加数据尾指针向右增加...加到头回到首地址

    从里面读数据头指针向右增加...加到头回到首地址

     

     注意      

    还是在唠叨唠叨

     

     

     

     

    rb_t pRb; ///< 环形缓冲区结构体变量
    uint8_t rbBuf[RB_MAX_LEN]; ///< 环形缓冲区数据缓存区

    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;//尾指向数组首地址
    }

    void rbDelete(rb_t* rb)//删除一个环形缓冲区
    {
    if(NULL == rb)
    {
    printf("ERROR: input rb is NULL\n");
    return;
    }

    rb->rbBuff = NULL;//地址赋值为空
    rb->rbHead = NULL;//头地址为空
    rb->rbTail = NULL;//尾地址尾空
    rb->rbCapacity = 0;//长度为空
    }

    int32_t rbCapacity(rb_t *rb)//获取链表的长度
    {
    if(NULL == rb)
    {
    printf("ERROR: input rb is NULL\n");
    return -1;
    }

    return rb->rbCapacity;
    }

    int32_t rbCanRead(rb_t *rb)//返回能读的空间
    {
    if(NULL == rb)
    {
    printf("ERROR: input rb is NULL\n");
    return -1;
    }

    if (rb->rbHead == rb->rbTail)//头与尾相遇
    {
    return 0;
    }

    if (rb->rbHead < rb->rbTail)//尾大于头
    {
    return rb->rbTail - rb->rbHead;
    }

    return rbCapacity(rb) - (rb->rbHead - rb->rbTail);//头大于尾
    }

    int32_t rbCanWrite(rb_t *rb)//返回能写入的空间
    {
    if(NULL == rb)
    {
    printf("ERROR: input rb is NULL\n");
    return -1;
    }

    return rbCapacity(rb) - rbCanRead(rb);//总的减去已经写入的空间
    }

    /*
    rb--要读的环形链表
    data--读出的数据
    count--读的个数
    */
    int32_t rbRead(rb_t *rb, void *data, size_t count)
    {
    int copySz = 0;

    if(NULL == rb)
    {
    printf("ERROR: input rb is NULL\n");
    return -1;
    }

    if(NULL == data)
    {
    printf("ERROR: input data is NULL\n");
    return -1;
    }

    if (rb->rbHead < rb->rbTail)//尾大于头
    {
    copySz = min(count, rbCanRead(rb));//查看能读的个数
    memcpy(data, rb->rbHead, copySz);//读出数据到data
    rb->rbHead += copySz;//头指针加上读取的个数
    return copySz;//返回读取的个数
    }
    else //头大于等于了尾
    {
    if (count < rbCapacity(rb)-(rb->rbHead - rb->rbBuff))//读的个数小于头上面的数据量
    {
    copySz = count;//读出的个数
    memcpy(data, rb->rbHead, copySz);//
    rb->rbHead += copySz;
    return copySz;
    }
    else//读的个数大于头上面的数据量
    {
    copySz = rbCapacity(rb) - (rb->rbHead - rb->rbBuff);//先读出来头上面的数据
    memcpy(data, rb->rbHead, copySz);
    rb->rbHead = rb->rbBuff;//头指针指向数组的首地址
    //还要读的个数
    copySz += rbRead(rb, (char*)data+copySz, count-copySz);//接着读剩余要读的个数
    return copySz;
    }
    }
    }

    int32_t rbWrite(rb_t *rb, const void *data, size_t count)
    {
    int tailAvailSz = 0;

    if(NULL == rb)
    {
    printf("ERROR: rb is empty \n");
    return -1;
    }

    if(NULL == data)
    {
    printf("ERROR: data is empty \n");
    return -1;
    }

    if (count >= rbCanWrite(rb))//如果剩余的空间不够
    {
    printf("ERROR: no memory \n");
    return -1;
    }

    if (rb->rbHead <= rb->rbTail)//头小于等于尾
    {
    tailAvailSz = rbCapacity(rb) - (rb->rbTail - rb->rbBuff);//查看尾上面剩余的空间
    if (count <= tailAvailSz)//个数小于等于尾上面剩余的空间
    {
    memcpy(rb->rbTail, data, count);//拷贝数据到环形数组
    rb->rbTail += count;//尾指针加上数据个数
    if (rb->rbTail == rb->rbBuff+rbCapacity(rb))//正好写到最后
    {
    rb->rbTail = rb->rbBuff;//尾指向数组的首地址
    }
    return count;//返回写入的数据个数
    }
    else
    {
    memcpy(rb->rbTail, data, tailAvailSz);//填入尾上面剩余的空间
    rb->rbTail = rb->rbBuff;//尾指针指向数组首地址
    //剩余空间 剩余数据的首地址 剩余数据的个数
    return tailAvailSz + rbWrite(rb, (char*)data+tailAvailSz, count-tailAvailSz);//接着写剩余的数据
    }
    }
    else //头大于尾
    {
    memcpy(rb->rbTail, data, count);
    rb->rbTail += count;
    return count;
    }
    }
    /**@} */

    /**
    * @brief 向环形缓冲区写入数据
    * @param [in] buf : buf地址
    * @param [in] len : 字节长度
    * @return 正确 : 返回写入的数据长度
    失败 : -1
    */
    int32_t PutData(uint8_t *buf, uint32_t len)
    {
    int32_t count = 0;

    if(NULL == buf)
    {
    printf("ERROR: gizPutData buf is empty \n");
    return -1;
    }

    count = rbWrite(&pRb, buf, len);
    if(count != len)
    {
    printf("ERROR: Failed to rbWrite \n");
    return -1;
    }
    USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
    return count;
    }

     

    #ifndef LOOPLIST_H_
    #define LOOPLIST_H_

    #ifndef LOOPLIST_C_//如果没有定义 AnnularArray_C_
    #define LOOPLIST_C_ extern
    #else
    #define LOOPLIST_C_
    #endif

    #include <stm32f10x.h>

    #define size_t uint16_t

    #define RB_MAX_LEN 1024 //缓冲区最大长度
    #define min(a, b) (a)<(b)?(a):(b) ///< 获取最小值

    /** 环形缓冲区数据结构 */
    typedef struct {
    size_t rbCapacity;//空间大小
    uint8_t *rbHead; //头
    uint8_t *rbTail; //尾
    uint8_t *rbBuff; //数组的首地址
    }rb_t;

    LOOPLIST_C_ rb_t pRb; ///< 环形缓冲区结构体变量
    LOOPLIST_C_ uint8_t rbBuf[RB_MAX_LEN]; ///< 环形缓冲区数据缓存区

    LOOPLIST_C_ void rbCreate(rb_t *rb,u8 *Buff,uint32_t BuffLen);//创建或者说初始化环形缓冲区
    LOOPLIST_C_ void rbDelete(rb_t* rb);
    LOOPLIST_C_ int32_t rbCapacity(rb_t *rb);//得到环形大小
    LOOPLIST_C_ int32_t rbCanRead(rb_t *rb);//能读出数据的个数
    LOOPLIST_C_ int32_t rbCanWrite(rb_t *rb);//还剩余的空间
    LOOPLIST_C_ int32_t rbRead(rb_t *rb, void *data, size_t count);//读取数据
    LOOPLIST_C_ int32_t rbWrite(rb_t *rb, const void *data, size_t count);
    LOOPLIST_C_ int32_t PutData(uint8_t *buf, uint32_t len);


    #endif

     

    #include "include.h"

    uint8_t aaa[50]={1,1,1,1,1,1,1,1,1,1};

    uint8_t bbb[50]={3,3,3,3,3,3,3,3,3,3};
    int main(void)
    {
    NVIC_Configuration();
    Led_Gpio_Init();
    Timer2_Config();
    uart_init(115200); //串口初始化为115200
    rbCreate(&pRb,SendBuff,USART_REC_LEN);//创建环形队列
    while(1)
    {
    PutData(aaa,10);//发送数据
    PutData(bbb,10);//发送数据
    delay_ms(10);
    }
    }

     

    void USART1_IRQHandler(void) //串口1中断服务程序
    {
    u8 Res;

    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
    {
    Res =USART_ReceiveData(USART1); //读取接收到的数据
    }
    if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)
    {
    if(rbCanRead(&pRb)>0)//如果里面的数据个数大于0
    {
    rbRead(&pRb, &SendDat, 1);//读取一个数据
    USART_SendData(USART1, SendDat);//发送
    }
    else
    {
    //发送字节结束
    USART_ClearITPendingBit(USART1,USART_IT_TXE);
    USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
    USART_ITConfig(USART1, USART_IT_TC, ENABLE);
    }
    }
    //发送完成
    if (USART_GetITStatus(USART1, USART_IT_TC) != RESET)
    {
    USART_ClearITPendingBit(USART1,USART_IT_TC);
    USART_ITConfig(USART1, USART_IT_TC, DISABLE);
    }
    }

     

    其实再完美点就是加上DMA....后期我尽量用LPC的单片机做....不对是一定要用LPC的单片机做成dma的---

     

      程序链接:http://pan.baidu.com/s/1pLlXDfP 密码:6kci

     

    转载于:https://www.cnblogs.com/wolf-man/p/10875482.html

    展开全文
  • STM32串口发送数据和接收数据方式总结

    万次阅读 多人点赞 2018-05-13 20:34:22
    之前写了篇关于ESP8266使用AT指令进行互相通讯的实验,在写STM...串口发送数据: 1. 串口发送数据最直接的方式就是标准调用库函数。void USART_SendData(USART_TypeDef* USARTx, uint16_t Data); 第一个参数是发送...

     

           之前写了篇关于ESP8266使用AT指令进行互相通讯的实验,在写STM32串口接发数据的程序中,觉得有必要将之前学的有关于串口方面的使用经历加以总结。

     

    串口发送数据:

           1. 串口发送数据最直接的方式就是标准调用库函数  void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
    第一个参数是发送的串口号,第二个参数是要发送的数据了。但是用过的朋友应该觉得不好用,一次只能发送单个字符,所以我们有必要根据这个函数加以扩展。

    void Send_data(u8 *s)
    {
    	while(*s!='\0')
    	{ 
    		while(USART_GetFlagStatus(USART1,USART_FLAG_TC )==RESET);	
    		USART_SendData(USART1,*s);
    		s++;
    	}
    }

            以上程序的形参就是我们调用该函数时要发送的字符串,这里通过循环调用USART_SendData来一 一发送我们的字符串。

    while(USART_GetFlagStatus(USART1,USART_FLAG_TC )==RESET);

             这句话有必要加,他是用于检查串口是否发送完成的标志,如果不加这句话会发生数据丢失的情况。这个函数只能用于串口1发送。有些时候根据需要,要用到多个串口发送那么就还需要改进这个程序。如下: 

    void Send_data(USART_TypeDef * USARTx,u8 *s)
    {
    	while(*s!='\0')
    	{ 
    		while(USART_GetFlagStatus(USARTx,USART_FLAG_TC )==RESET);	
    		USART_SendData(USARTx,*s);
    		s++;
    	}
    }

            这样就可实现任意的串口发送。但有一点,我在使用实时操作系统的时候(如UCOS,Freertos等),需考虑函数重入的问题。当然也可以简单的实现把该函数复制一下,然后修改串口号也可以避免该问题。然而这个函数不能像printf那样传递多个参数,所以还可以在改进,最终程序如下

    void USART_printf ( USART_TypeDef * USARTx, char * Data, ... )
    {
    	const char *s;
    	int d;   
    	char buf[16];
    	
    	va_list ap;
    	va_start(ap, Data);
    
    	while ( * Data != 0 )     // 判断是否到达字符串结束符
    	{				                          
    		if ( * Data == 0x5c )  //'\'
    		{									  
    			switch ( *++Data )
    			{
    				case 'r':							          //回车符
    				USART_SendData(USARTx, 0x0d);
    				Data ++;
    				break;
    
    				case 'n':							          //换行符
    				USART_SendData(USARTx, 0x0a);	
    				Data ++;
    				break;
    
    				default:
    				Data ++;
    				break;
    			}			 
    		}
    		
    		else if ( * Data == '%')
    		{									  //
    			switch ( *++Data )
    			{				
    				case 's':										  //字符串
    				s = va_arg(ap, const char *);
    				
    				for ( ; *s; s++) 
    				{
    					USART_SendData(USARTx,*s);
    					while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );
    				}
    				
    				Data++;
    				
    				break;
    
    				case 'd':			
    					//十进制
    				d = va_arg(ap, int);
    				
    				itoa(d, buf, 10);
    				
    				for (s = buf; *s; s++) 
    				{
    					USART_SendData(USARTx,*s);
    					while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );
    				}
    				
    				Data++;
    				
    				break;
    				
    				default:
    				Data++;
    				
    				break;
    				
    			}		 
    		}
    		
    		else USART_SendData(USARTx, *Data++);
    		
    		while ( USART_GetFlagStatus ( USARTx, USART_FLAG_TXE ) == RESET );
    		
    	}
    }

            该函数就可以像printf使用可变参数,方便很多。通过观察函数但这个函数只支持了%d,%s的参数,想要支持更多,可以仿照printf的函数写法加以补充。
            2. 直接使用printf函数。        很多朋友都知道想要STM32要直接使用printf不行的。需要加上以下的重映射函数

           如果不想添加以上代码,也可以勾选以下的Use MicroLI选项来支持printf函数使用。

     

    串口接收数据:       

            串口接收最后应有一定的协议,如发送一帧数据应该有头标志或尾标志,也可两个标志都有。这样在处理数据时既能能保证数据的正确接收,也有利于接收完后我们处理数据。串口的配置在这里就不在赘述,这里我以串口2接收中断服务程序函数且接收的数据包含头尾标识为例。

    #define Max_BUFF_Len 18
    unsigned char Uart2_Buffer[Max_BUFF_Len];
    unsigned int Uart2_Rx=0;
    void USART2_IRQHandler() 
    {
    	if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //中断产生 
    	{
    		USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志
    			 
    		Uart2_Buffer[Uart2_Rx] = USART_ReceiveData(USART2);     //接收串口1数据到buff缓冲区
    		Uart2_Rx++; 
         		 
    		if(Uart2_Buffer[Uart2_Rx-1] == 0x0a || Uart2_Rx == Max_BUFF_Len)    //如果接收到尾标识是换行符(或者等于最大接受数就清空重新接收)
    		{
    			if(Uart2_Buffer[0] == '+')                      //检测到头标识是我们需要的 
    			{
    				printf("%s\r\n",Uart2_Buffer);        //这里我做打印数据处理
    				Uart2_Rx=0;                                   
    			} 
    			else
    			{
    				Uart2_Rx=0;                                   //不是我们需要的数据或者达到最大接收数则开始重新接收
    			}
    		}
    	}
    }

     


            数据的头标识为“\n”既换行符,尾标识为“+”。该函数将串口接收的数据存放在USART_Buffer数组中,然后先判断当前字符是不是尾标识,如果是说明接收完毕,然后再来判断头标识是不是“+”号,如果还是那么就是我们想要的数据,接下来就可以进行相应数据的处理了。但如果不是那么就让Usart2_Rx=0重新接收数据。这样做的有以下好处:

            1.可以接受不定长度的数据,最大接收长度可以通过Max_BUFF_Len来更改

            2.可以接受指定的数据

            3.防止接收的数据使数组越界
            这里我的把接受正确数据直接打印出来,也可以通过设置标识位,然后在主函数里面轮询再操作。

            

            以上的接收形式,是中断一次就接收一个字符,这在UCOS等实时内核系统中频繁的中断,非常消耗CPU资源,在有些时候我们需要接收大量数据时且波特率很高的情况下,长时间中断会带来一些额外的问题。所以以DMA形式配合串口的IDLE(空闲中断)来接受数据将会大大的提高CPU的利用率,减少系统资源的消耗。首先还是先看代码。

    #define DMA_USART1_RECEIVE_LEN 18
    void USART1_IRQHandler(void)                                 
    {     
        u32 temp = 0;  
        uint16_t i = 0;  
          
        if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)  
        {  
            USART1->SR;  
            USART1->DR; //这里我们通过先读SR(状态寄存器)和DR(数据寄存器)来清USART_IT_IDLE标志 			
            DMA_Cmd(DMA1_Channel5,DISABLE);  
            temp = DMA_USART1_RECEIVE_LEN - DMA_GetCurrDataCounter(DMA1_Channel5); //接收的字符串长度=设置的接收长度-剩余DMA缓存大小 
            for (i = 0;i < temp;i++)  
            {  
                Uart2_Buffer[i] = USART1_RECEIVE_DMABuffer[i];  
                    
            }  
            //设置传输数据长度  
            DMA_SetCurrDataCounter(DMA1_Channel5,DMA_USART1_RECEIVE_LEN);  
            //打开DMA  
            DMA_Cmd(DMA1_Channel5,ENABLE);  
        }        
    } 

            之前的串口中断是一个一个字符的接收,现在改为串口空闲中断,就是一帧数据过来才中断进入一次。而且接收的数据时候是DMA来搬运到我们指定的缓冲区(也就是程序中的USART1_RECEIVE_DMABuffer数组),是不占用CPU时间资源的。具体什么是IDLE中断和DMA需要朋友们先行了解。

        参考链接:

        https://blog.csdn.net/jdh99/article/details/8444474

        https://blog.csdn.net/phker/article/details/51925668   

       最后在讲下DMA的发送

    #define DMA_USART1_SEND_LEN 64
    void DMA_SEND_EN(void)
    {
    	DMA_Cmd(DMA1_Channel4, DISABLE);      
    	DMA_SetCurrDataCounter(DMA1_Channel4,DMA_USART1_SEND_LEN);   
    	DMA_Cmd(DMA1_Channel4, ENABLE);
    }

            这里需要注意下DMA_Cmd(DMA1_Channel4,DISABLE)函数需要在设置传输大小之前调用一下,否则不会重新启动DMA发送。

        有了以上的接收方式,对一般的串口数据处理是没有问题的了。下面再讲一下,在ucosiii中我使用信号量+消息队列+储存管理的形式来处理我们的串口数据。先来说一下这种方式对比其他方式的一些优缺点。一般对串口的处理形式是"生产者"和"消费者"的模式,即本次接收的数据要马上处理,否则当数据大量涌进的时候,就来不及"消费"掉生产者(串口接收中断)的数据,那么就会丢失本次的数据处理。所以使用队列就能够很方便的解决这个问题。

        在下面的程序中,对数据的处理是先接受,在处理,如果在处理的过程中,有串口中断接受数据,那么就把它依次放在队列中,队列的特征是先进先出,在串口中就是先处理先接受的数据,所以根据生产和消费的速度,定义不同大小的消息队列缓冲区就可以了。缺点就是太占用系统资源,一般51单片机是没可能了。下面是从我做的项目中截取过来的程序

    OS_MSG_SIZE  Usart1_Rx_cnt;          //字节大小计数值
    unsigned char Usart1_data;           //每次中断接收的数据
    unsigned char* Usart1_Rx_Ptr;        //储存管理分配内存的首地址的指针
    unsigned char* Usart1_Rx_Ptr1;       //储存首地址的指针
    void USART1_IRQHandler() 
    {
    	OS_ERR err;
    	OSIntEnter();
    	
      if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE) != RESET) //中断产生 
      { 	 
        USART_ClearFlag(USART1, USART_FLAG_RXNE);     //清除中断标志
    		
        Usart1_data = USART_ReceiveData(USART1);     //接收串口1数据到buff缓冲区
    		
    		if(Usart1_data =='+')                     //接收到数据头标识
    		{
    //			OSSemPend((OS_SEM*		)&SEM_IAR_UART,  //这里请求信号量是为了保证分配的存储区,但一般来说不允许
    //			(OS_TICK		)0,                   //在终端服务函数中调用信号量请求但因为
    //			(OS_OPT			)OS_OPT_PEND_NON_BLOCKING,//我OPT参数设置为非阻塞,所以可以这么写
    //			(CPU_TS*		)0,
    //			(OS_ERR*		)&err); 
    //			if(err==OS_ERR_PEND_WOULD_BLOCK)	    //检测到当前信号量不可用
    //			{
    //				 printf("error");
    //			}				
    			Usart1_Rx_Ptr=(unsigned char*) OSMemGet((OS_MEM*)&UART1_MemPool,&err);//分配存储区
    			Usart1_Rx_Ptr1=Usart1_Rx_Ptr;		        //储存存储区的首地址
    		}
    		if(Usart1_data == 0x0a )   				//接收到尾标志
    		{                    
    			*Usart1_Rx_Ptr++=Usart1_data;
    			Usart1_Rx_cnt++;                        	//字节大小增加
    			OSTaskQPost((OS_TCB    *  )&Task1_TaskTCB,
                                       (void      *  )Usart1_Rx_Ptr1,    //发送存储区首地址到消息队列
                                       (OS_MSG_SIZE  )Usart1_Rx_cnt,
                                       (OS_OPT       )OS_OPT_POST_FIFO,  //先进先出,也可设置为后进先出,再有地方很有用
                                       (OS_ERR    *  )&err);
    									
    			Usart1_Rx_Ptr=NULL;          //将指针指向为空,防止修改
    			Usart1_Rx_cnt=0;	     //字节大小计数清零
    		}
    		else
    		{
    			*Usart1_Rx_Ptr=Usart1_data; //储存接收到的数据
    			Usart1_Rx_Ptr++;
    			Usart1_Rx_cnt++;
    		}	
    	}		 	
    	OSIntExit();
    }

           上面被注释掉的代码为我是为了防止当分区中没有空闲的存储块时加入信号量,打印出报警信息。当然我们也可以将存储块直接设置大一点,但是还是无法避免当没有可有存储块时会程序会崩溃现象。希望懂的朋友能告知下~。

            下面是串口数据处理任务,这里删去了其他代码,只把他打印出来了而已。

    void task1_task(void *p_arg)
    {
    	OS_ERR err;
    	OS_MSG_SIZE Usart1_Data_size;
    	u8 *p;
    	
    	while(1)
    	{
    		p=(u8*)OSTaskQPend((OS_TICK		)0, //请求消息队列,获得储存区首地址
    			(OS_OPT				)OS_OPT_PEND_BLOCKING,
    			(OS_MSG_SIZE*	)&Usart1_Data_size,
    			(CPU_TS*			)0,
    			(OS_ERR*			)&err);
    
    		printf("%s\r\n",p);        //打印数据
    
    		delay_ms(100);
    		OSMemPut((OS_MEM*	)&UART1_MemPool,    //释放储存区
    		(void*			)p,
    		(OS_ERR*		)&err);
    						 
    		OSSemPost((OS_SEM*	)&SEM_IAR_UART,    //释放信号量
    		(OS_OPT 	)OS_OPT_POST_NO_SCHED,
    		(OS_ERR*	)&err);
    						 
    		OSTimeDlyHMSM(0,0,1,500,OS_OPT_TIME_PERIODIC,&err);				 
    	}
    }

     

     

     

    展开全文
  • c# 串口发送数据c# 串口发送数据c# 串口发送数据c# 串口发送数据
  • 实现芯片串口收发数据,按键中断串口发送数据:按下按键,向串口发送数据,并通过虚拟终端显示出来; 串口接收数据中断来控制LED亮/灭:通过串口助手向MCU发送数据,“A”把LED灯点亮,“B”把LED灯熄灭。 led_key.c...

    实验目的:
    实现芯片串口收发数据,按键中断串口发送数据:按下按键,向串口发送数据,并通过虚拟终端显示出来;
    串口接收数据中断来控制LED亮/灭:通过串口助手向MCU发送数据,“A”把LED灯点亮,“B”把LED灯熄灭。

    led_key.c

    #include "stm32f4xx.h" 
    #include "bitband.h"
    void led_init()//PD0、PD1、PD2、PD3
    {
    	GPIO_InitTypeDef d;
    	/*使能GPIOD的时钟*/
    	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);
    	
    	/*配置PD0-PD6,为输出模,输出推挽类型,低速模式*/
    	d.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3| GPIO_Pin_4| GPIO_Pin_5| GPIO_Pin_6;
    	d.GPIO_Mode = GPIO_Mode_OUT;
    	d.GPIO_OType = GPIO_OType_PP;
    	d.GPIO_Speed = GPIO_Low_Speed;
    	GPIO_Init(GPIOD, &d);
    }
    
    void key_init()
    {       /*按键初始化*/
    	GPIO_InitTypeDef b;
    	/*使能GPIOB的时钟*/
    	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
    	
    	
    	/*配置PB2,PB6为输入模式,上拉,按下去就会变成低电平*/
    	b.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_6;
    	b.GPIO_Mode = GPIO_Mode_IN;
    	b.GPIO_PuPd = GPIO_PuPd_UP;
    	GPIO_Init(GPIOB, &b);
    
    }
    
    void led_control(int led_num,int status)
    {
    	switch(led_num)
    	{
    		case 0:
    	  	PDout(0) = status;
    			break;
    		case 1:
    			PDout(1) = status;
    			break;
    		case 2:
    			PDout(2) = status;
    			break;
    		case 3:
    			PDout(3) = status;
    			break;	
    			case 4:
    			PDout(4) = status;
    			break;	
    			case 5:
    			PDout(5) = status;
    			break;	
    			case 6:
    			PDout(6) = status;
    			break;	
    }
    	}
    
    	/*all_led_control,根据state的每一位来控制所有的LED灯*/
    	void all_led_control(unsigned char state)
    	{
    		PDout(0)=!!(state&(1<<0));    //!!把真变成1,把假变成0;
    	  PDout(1)=!!(state&(1<<1)); 
    		PDout(2)=!!(state&(1<<2)); 
    		PDout(3)=!!(state&(1<<3)); 
    		PDout(4)=!!(state&(1<<4)); 
    		PDout(5)=!!(state&(1<<5)); 
    		PDout(6)=!!(state&(1<<6)); 	
    	}
    	
    int key_status(int key_num)
    {
    	switch(key_num)
    	{
    		case 0:
    			return PBin(2);
    		case 1:
    			return PBin(6);
    	}
    	return -1;
    }
    
    void motor_init(void)//PA4
    {
    	GPIO_InitTypeDef a;
    	/*使能GPIOA的时钟*/
    	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
    	
    	/*配置PA4为输出模,输出推挽类型,低速模式*/
    	a.GPIO_Pin = GPIO_Pin_4 ;
    	a.GPIO_Mode = GPIO_Mode_OUT;
    	a.GPIO_OType = GPIO_OType_PP;
    	a.GPIO_Speed = GPIO_Low_Speed;
    	GPIO_Init(GPIOA, &a);
    
    	PAout(4) = 0;
    }
    
    void motor_control(int status)
    {
    	PAout(4) = status;
    }
    
    void beep_init(void)//PB12
    {
    	GPIO_InitTypeDef b;
    	/*使能GPIOB的时钟*/
    	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
    	
    	/*配置PB12为输出模,输出推挽类型,低速模式*/
    	b.GPIO_Pin = GPIO_Pin_12 ;
    	b.GPIO_Mode = GPIO_Mode_OUT;
    	b.GPIO_OType = GPIO_OType_PP;
    	b.GPIO_Speed = GPIO_Low_Speed;
    	GPIO_Init(GPIOB, &b);
    
    	PBout(12) = 0;
    }
    
    void beep_control(int status)
    {
    	PBout(12) = status;
    }
    
    
    
    
    

    uart.c

    #include "uart.h"
    #include "led_key.h"
    void usart1_init(uint32_t BaudRate)  //PA9,PA10
    {
    	   
         /*GPIO口配置*/
    		GPIO_InitTypeDef GPIO_InitStruct;
    	
    	   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);  //使能时钟
    	   GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9|GPIO_Pin_10;
    	   GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;       //复用模式
    	   GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
    	   GPIO_InitStruct.GPIO_Speed=GPIO_High_Speed;    //速率
    	   GPIO_Init(GPIOA,&GPIO_InitStruct);//GPIO初始化;
    	
    	   GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);//指定复用功能
    	   GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);//指定复用功能
    	
    	  /*USART配置*/
    	   USART_InitTypeDef USART_InitStruct;
    	
    	  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能串口时钟
    	  USART_InitStruct.USART_BaudRate=BaudRate;//设置波特率
    	  USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//无流控
    	  USART_InitStruct.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;//发送接收模式
    	  USART_InitStruct.USART_Parity=USART_Parity_No;     //无校验
    	  USART_InitStruct.USART_StopBits=USART_StopBits_1;    //1个停止位
    		 USART_InitStruct.USART_WordLength=USART_WordLength_8b;    //8位数据长度
    		 USART_Init(USART1,&USART_InitStruct);
    		 
    		/*中断配置*/
    		NVIC_InitTypeDef NVIC_InitStruct;
    		
    		USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);   //来数据触发中断使能;
    		NVIC_InitStruct.NVIC_IRQChannel=USART1_IRQn;   //中断通道配置
    		NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
    		NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0x02;
    		NVIC_InitStruct.NVIC_IRQChannelSubPriority=0x02;
    		NVIC_Init(&NVIC_InitStruct);
    
        /*使能串口*/
    		USART_Cmd(USART1,ENABLE);
    
    }
    
    
    
    /*USART1的中断处理函数*/
    void USART1_IRQHandler(void)
    {
       unsigned char data;
    	if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)
    	{
    	   data=USART_ReceiveData(USART1);
    		
    		if(data=='A')
    		{
            led_control(0,1);	
            led_control(1,1);	
            led_control(2,1);	
            led_control(3,1);				
    		
    		}
    		else if(data=='B')
    		{
            led_control(0,0);	
            led_control(1,0);	
            led_control(2,0);	
            led_control(3,0);				
    		}
    		
    	  USART_ClearITPendingBit(USART1,USART_IT_RXNE);  //清空标志位
    	
    	}
    
    }
    
    /* 串口数据的发送*/
    void USART_SendDatas(USART_TypeDef * USARTx,unsigned char *dataBuf,int len)
    {   
         int i;
    	    for(i=0;i<len;i++)
    	{       
    	     USART_SendData(USARTx,dataBuf[i]);
    		//等待发送完成
    		while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE)==RESET);
    	
    	}
    }
    

    main.c

    #include "main.h"
    #include "led_key.h"
    #include "delay.h"
    //#include "timer.h"
    #include "uart.h"
    
    unsigned char str1[] = { "Hello, how are you?\n" };
    unsigned char str2[] = { "Fine, thank you, and you?\n" };
    
    int main(){ 
    
        led_init();
    	  key_init();
    	  usart1_init(9600);
    	
    	while(1){
    		
    		if (key_status(0) == 0)
    		{
    			USART_SendDatas(USART1, str1, sizeof(str1));
    			delay_ms(200);
    		}
    		
    		if (key_status(1) == 0)
    		{
    			USART_SendDatas(USART1, str2, sizeof(str2));
    			delay_ms(200);
    		}
    	}
     
    }
    
    
    

    实验框图:
    在这里插入图片描述

    实验现象:
    视频演示链接:https://www.bilibili.com/video/BV1Pi4y1x7q1
    部分截图
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在串口调试助手中发送B,灯全部熄灭
    在这里插入图片描述

    记录一个实验中遇到的问题:
    唯一一个问题就是VSPD和串口调试助手的使用。成功仿真了一次后,想要再仿真第二次,但是提示说“串口不存在或串口被占用”,于是我到注册列表中将串口全部关闭,此时VSPD已经显示串口处于关闭状态,但是打开串口调试助手还是出现提醒“串口不存在或串口被占用”。于是我想在VSPD中把这两个串口删除重新创建,但是删不掉,提示说“串口已经打开,无法删除”,但VSPD中显示串口是关闭状态并且注册列表中也将串口删除,于是我到设备管理器中卸载虚拟串口,再次尝试,还是失败。上网查了一下,发现不少人和我有一样的问题,只要把VPSD卸载重新安装并且将电脑重新启动就好了。

    展开全文
  • 在使用串口发送数据时可以选择字符串发送或者十六进制发送,通常情况下我们习惯选用字符串发送数据。关于两者的区别,需要从计算机存储数据的格式说起。 在计算机中,数据是以二进制的形式存储的,例如十进制 1(10)...
    5121aa844dceb58419c52c1a1e5f40fe.png

    在使用串口发送数据时可以选择字符串发送或者十六进制发送,通常情况下我们习惯选用字符串发送数据。关于两者的区别,需要从计算机存储数据的格式说起。

    在计算机中,数据是以二进制的形式存储的,例如十进制 1(10)在计算机中用 0000 0001(2)来表示。我们在用串口发送数据的时候首先将待数据转换为对应的ASCII码,然后再将这些ASCII码按照二进制的方式一位一位的发送出去。

    例如我们要发送一串数据“A852010100000000A91A”,以字符串和十六进制两种方式发送:(1)字符串发送

    串口以字符串发送数据,首先将字符串转化为二进制,格式如下:

    35501bafa8f2624f9b71415a1808f621.png

    然后按照8位(串口设置数据位为8位)形式将数据发送出去。

    串口接收的数据格式如下:

    b0d07a42f41ad039e2d54cbb97b2a8a9.png

    (2)十六进制发送数据

    串口以十六进制发送数据,首先将数据转化为:

    4713724b23409066b5da8c321729627b.png

    然后按照8位(串口设置数据位为8位)形式将数据发送出去。

    串口接收的数据格式如下:

    96207d0898896f7e60c5415fb2d8d709.png

    仔细对照接收结果就很容易明白字符串发送和十六进制发送的区别了。

    附转换:

    1. //转换每一个字符为正真的16进制数值
    2. char Widget::ConvertHexChar(char ch)
    3. {
    4. if((ch >= '0') && (ch <= '9'))
    5. return ch-0x30;
    6. else if((ch >= 'A') && (ch <= 'F'))
    7. return ch-'A'+10;
    8. else if((ch >= 'a') && (ch <= 'f'))
    9. return ch-'a'+10;
    10. else return (-1);
    11. }
    展开全文
  • 之前写了篇关于ESP8266使用AT指令进行互相...串口发送数据: 1. 串口发送数据最直接的方式就是标准调用库函数。void USART_SendData(USART_TypeDef* USARTx, uint16_t Data); 第一个参数是发送的串口号,第二个参数...
  • S 串口编程 详解4 串口发送数据

    千次阅读 2013-10-31 11:39:25
    S 串口编程 详解4 串口发送数据 串口发送数据包括: 十六进制发送数据 手动发送数据 自动发送数据 手动发送数据的代码如下: //手动发送 long TX_count=0; void CSCOMMDlg::OnButtonManualsend() { if...
  • 基于STM32F103 处理器的串口发送数据程序,使用输入输出重定向,在程序中可以使用 printf scanf
  • 原文:WPF内实现与串口发送数据和接收数据 与串口发送数据和接收数据,在此作一个简单的Demo.此Demo可以实现按下硬件按钮,灯亮,发送灯状态数据过来。并且可以实现几个灯同时亮,发送灯的...
  • 51单片机 串口发送数据(只是发送)用于调试。 #include <reg51.h> #define uchar unsigned char #define uint unsigned int #define XTAL 11059200 // CUP 晶振频率 #define baudrate 9600 // 通信波特...
  • timestamp=1563807838&req_id=201907222303570100230601438916BD5&group_id=67160264916892390441、这节课我们来实现串口的写入与接收,同样查看pyseri...
  • C#做个PC串口发送数据

    2020-05-24 14:30:40
    C#做个PC串口发送数据 try//防止出错 { serialPort1.Open();//打开串口 serialPort1.Write(buffer, 0, 1);//发送串口 serialPort1.Close();//关闭串口 } catch {//如果出错就执行此块代码 if (serialPort1
  • 串口发送数据如下: C0 C0 02 02 F0 F2 CF ,用串口调试工具发送这样的命令,摄像头无反应。但是勾选16进制发送就能成功控制!现在在c#中编写串口发送,摄像头也没有反应,我就想知道如果才能让输入的上面的...
  • OpenMV串口发送图片# Hello World Example## Welcome to the OpenMV IDE! Click on the green run arrow button below to run the script!import sensor, image, timefrom pyb import UARTuart = UART(3)uart.init...
  • 接线 星瞳教程 发送数据 接收数据 不过我比较奇怪为何它们的uart不需要初始化 openmv传送数据 1、初始化以及uart参数设置 uart pyb.UART(3, 115200) #串口3 波特率115200uart.init(115目录参考接线星瞳教程openmv...
  • 我们在用串口发送数据的时候首先将待发送的数据/符号转换为对应的ASCII码,然后将这些ASCII码按照二进制的方式一位一位地发送出去。 (注:以下图片来自https://blog.csdn.net/wityy/article/details/8234739) ...
  • 所以用点亮LED引脚模拟串口发送数据就很方便,不用再去初始化串口IO,初始化串口等等。 /** * @brief 软件模拟串口发送数据 * @param 48MHz时钟,9600波特率,8数据位,无校验 * @retva...
  • 基于c51单片机的数据采集串口发送数据到pc的C程序
  • STM串口发送数据无法发送第一个数据的解决方法
  • USART---串口发送数据

    千次阅读 2015-01-06 22:42:43
    USART---串口发送数据---完全解读
  • 使用串口发送数据时,需要一个字节一个字节地发送,所以发送非char类型数据比较困难,比如发送一个int类型数据或者是一个double类型数据。这时,联合体的作用就体现出来了。 联合体中的各数据项使用的是同一块内存...
  • python 用pyserial模块通过串口发送数据的注意点 最近开始在工作中开始边学边用python,其中需要用python实现串口读写,在编程调试过程中发现通过pyserial模块的write方法发送字符串时,数据并没有被发送去到串口...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,419
精华内容 4,967
关键字:

串口发送数据