精华内容
下载资源
问答
  • stm32串口通信流程图

    2020-12-18 19:37:51
    1.写在前面首先,你要知道STM32启动文件中启动流程,你就需要掌握一点汇编基础知识。汇编语言属于机器语言,或者说低级语言,C语言属于高级语言,所以,汇编和C语言在语法上差异很大。如果你学底层开发,汇编的一些...

    1.写在前面

    首先,你要知道STM32启动文件中启动流程,你就需要掌握一点汇编基础知识。

    汇编语言属于机器语言,或者说低级语言,C语言属于高级语言,所以,汇编和C语言在语法上差异很大。

    如果你学底层开发,汇编的一些基础知识需要掌握。不需要精通,但需要看懂常见的汇编代码。

    2.说明

    STM32的启动文件与编译器有关,不同编译器,它的启动文件不同。

    虽然启动文件(汇编)代码各有不同,但它们原理类似,都属于汇编程序。

    我们拿基于MDK-ARM的启动文件来举例,说一下要点内容。

    3.分配堆栈

    在基于MDK的启动文件开始,有一段汇编代码是分配堆栈大小的。

    这里重点知道堆栈数值大小就行。还有一段AREA(区域),表示分配一段堆栈数据段。

    数值大小可以自己修改,也可以使用STM32CubeMX数值大小配置:

    在IAR中,是通过工程配置堆栈大小:

    4.向量表

    相信大家都知道向量表,先看汇编代码:

    这个向量表就是对应手册中的那些内容:

    我们需要知道这个地方中的复位,程序上电之后,是跳到Reset_Handler这个位置。

    5.执行代码

    上面知道代码是从Reset_Handler开始执行,我们看Reset_Handler汇编代码:

    在启动的时候,执行了SystemInit这个函数。

    之前标准外设库在SystemInit这个函数初始化了系统时钟,后面HAL库单独把那部分代码提出来了。

    执行完SystemInit函数,就跳转到我们的main函数执行了。

    打开APP阅读更多精彩内容

    点击阅读全文

    展开全文
  • 串口接收流程 编程USARTx_CR1的M位来定义字长。 编程USARTx_CR2的STOP位来定义停止位位数。 编程USARTx_BRR寄存器确定波特率。 使能USARTx_CR1的UE位使能USARTx。 如果进行多缓冲通信,配置USARTx_CR3的DMA使能...

    串口接收

    串口接收流程

    1. 编程USARTx_CR1的M位来定义字长。
    2. 编程USARTx_CR2的STOP位来定义停止位位数。
    3. 编程USARTx_BRR寄存器确定波特率。
    4. 使能USARTx_CR1的UE位使能USARTx。
    5. 如果进行多缓冲通信,配置USARTx_CR3的DMA使能(DMAT)。
    6. 使能USARTx_CR1的RE位为1使能接收器。
    7. 如果要使能接收中断(接收到数据后产生中断),使能USARTx_CR1的RXNEIE位为1。

    当串口接收到数据时

    1. USARTx_SR(ISR)的RXNE位置1。表明移位寄存器内容已经传输到RDR(DR)寄存器。已经接收到数据并且等待读取。
    2. 如果开启了接收数据中断(USARTx_CR1寄存器的RXNEIE位为1),则会产生中断。(程序上会执行中断服务函数)
    3. 如果开启了其他中断(帧错误等),相应标志位会置1。
    4. 读取USARTx_RDR(DR)寄存器的值,该操作会自动将RXNE位清零,等待下次接收后置位。

    串口接收流程(HAL库)

    配置过程:

    接收配置步骤①~⑥和发送流程一样,调用HAL_UART_Init函数HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart);

    步骤⑦开启接收中断:HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef*huart, uint8_t *pData, uint16_t Size);

    接收数据过程:

    步骤①获取状态标志位通过标识符实现:

       __HAL_UART_GET_FLAG            //判断状态标志位
       __HAL_UART_GET_IT_SOURCE   //判断中断标志位
    

    步骤②~③中断服务函数:

    void USARTx_IRQHandler(void) ;//(x=1~3,6)
    void UARTx_IRQHandler(void) ;//(x=4,5,7,8)
    

    在启动文件startup_stm32fxxx.s中查找。
    步骤④读取接收数据:
    HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);

    串口接收中断程序配置过程(HAL库)

    1. 初始化串口相关参数,使能串口:HAL_UART_Init();
    2. 串口相关IO口配置,复用配置:
      在HAL_UART_MspInit中调用HAL_GPIO_Init函数。
    3. 串口接收中断优先级配置和使能:
      HAL_NVIC_EnableIRQ();
      HAL_NVIC_SetPriority();
    4. 使能串口接收中断:HAL_UART_Receive_IT();
    5. 编写中断服务函数:USARTx_IRQHandler

    经过上面步骤,我们就可以写完整的串口接收实验。我们就可以在中断服务函数中编写中断处理过程。
    HAL库提供了详细的中断处理函数HAL_UART_IRQHandler,我们在中断服务函数中会调用此函数处理中断。

    在这里插入图片描述

    在void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)函数里可以找到:UART_Receive_IT(huart);然后找到他的定义static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart),里面可以找到HAL_UART_RxCpltCallback(huart);他是一个接收完成处理回调函数,void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart),用户可以自己编写。

    在USART_HandleTypeDef中有如下变量:RxXferSize是接收的数量,RxXferCount是剩余的数据个数,pRxBuffPtr指向数据存储位置的地址。比如,一开始要接收10个数据,pRxBuffPtr指向一个起始位置,初始时RxXferSize=10,RxXferCount=10,每接收一次,RxXferCount的值就减去1,而且pRxBuffPtr指针往下移,直到RxXferCount减为0 。

      uint8_t                       *pRxBuffPtr;      /*!< Pointer to USART Rx transfer Buffer */
    
      uint16_t                      RxXferSize;       /*!< USART Rx Transfer size              */
    
      uint16_t                      RxXferCount;      /*!< USART Rx Transfer Counter           */
    
    static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)
    {
      uint16_t* tmp;
      uint16_t uhMask = huart->Mask;
    
      /* Check that a Rx process is ongoing */
      if(huart->RxState == HAL_UART_STATE_BUSY_RX)
      {
    
        if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
        {
          tmp = (uint16_t*) huart->pRxBuffPtr ;
          *tmp = (uint16_t)(huart->Instance->RDR & uhMask);
          huart->pRxBuffPtr +=2;
        }
        else
        {
          *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->RDR & (uint8_t)uhMask);
        }
    
        if(--huart->RxXferCount == 0)
        {
          /* Disable the UART Parity Error Interrupt and RXNE interrupt*/
          CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
    
          /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
          CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
    
          /* Rx process is completed, restore huart->RxState to Ready */
          huart->RxState = HAL_UART_STATE_READY;
    
          HAL_UART_RxCpltCallback(huart);
    
          return HAL_OK;
        }
    
        return HAL_OK;
      }
      else
      {
        /* Clear RXNE interrupt flag */
        __HAL_UART_SEND_REQ(huart, UART_RXDATA_FLUSH_REQUEST);
    
        return HAL_BUSY;
      }
    }
    

    串口接收中断流程

    在这里插入图片描述

    串口中断服务函数执行流程

    串口中断服务函数中调用HAL库串口中断通用处理函数:HAL_UART_IRQHandler(); 该函数会对中断来源进行分析,调用相应函数。
    对于不同的中断类型,我们只需要编写最终的中断处理函数:

    void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);
    void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);
    void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
    void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);
    void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart);
    

    串口接收实验

    电脑通过串口助手往串口1发送字符,串口1通过中断方式接受字符,每接受一个字符就同时通过串口1返回给电脑。

    1. 初始化串口相关参数,使能串口:HAL_UART_Init();
    2. 串口相关IO口配置,复用配置:
      在HAL_UART_MspInit中调用HAL_GPIO_Init函数。
    3. 串口接收中断优先级配置和使能:
      HAL_NVIC_EnableIRQ();
      HAL_NVIC_SetPriority();
    4. 使能串口接收中断:HAL_UART_Receive_IT();
    5. 编写中断服务函数:USARTx_IRQHandler

    根据如上步骤,其中1、2步骤和串口发送设置差不多,第三步,HAL_NVIC_SetPriority(USART1_IRQn,3,3);抢占和响应优先级均设置为3.这是因为main中的HAL_Init();有一个设置是 HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);

    #include "sys.h"
    #include "delay.h"
    #include "usart.h" 
    u8 rdata[1];//因为是每接收一个就发出去,所以设置为1
    UART_HandleTypeDef usart1_handler;
    //初始化串口相关参数,使能串口
    void uart1_init(void)
    {
    	usart1_handler.Instance = USART1;
    	usart1_handler.Init.BaudRate = 115200;
    	usart1_handler.Init.WordLength = UART_WORDLENGTH_8B;
    	usart1_handler.Init.StopBits = UART_STOPBITS_1;
    	usart1_handler.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    	usart1_handler.Init.Mode = UART_MODE_TX_RX;
    	usart1_handler.Init.Parity = UART_PARITY_NONE;
    	HAL_UART_Init(&usart1_handler);
    }
    //串口相关IO口配置,复用配置
    void HAL_UART_MspInit(UART_HandleTypeDef *huart)
    {
    	GPIO_InitTypeDef GPIO_Initure;
    	if(huart->Instance==USART1)
    	{
    		__HAL_RCC_GPIOA_CLK_ENABLE();			//使能GPIOA时钟
    		__HAL_RCC_USART1_CLK_ENABLE();			//使能USART1时钟
    		GPIO_Initure.Pin=GPIO_PIN_9;			//PA9
    		GPIO_Initure.Mode=GPIO_MODE_AF_PP;		//复用推挽输出
    		GPIO_Initure.Pull=GPIO_PULLUP;			//上拉
    		GPIO_Initure.Speed=GPIO_SPEED_HIGH;		//高速
    		GPIO_Initure.Alternate=GPIO_AF7_USART1;	//复用为USART1
    		HAL_GPIO_Init(GPIOA,&GPIO_Initure);	   	//初始化PA9
    
    		GPIO_Initure.Pin=GPIO_PIN_10;			//PA10
    		HAL_GPIO_Init(GPIOA,&GPIO_Initure);	   	//初始化PA10
            
            //串口接收中断优先级配置和使能
    		HAL_NVIC_SetPriority(USART1_IRQn,3,3);//设置中断优先级
    		HAL_NVIC_EnableIRQ(USART1_IRQn);//使能中断通道
    	}
    }
    //编写中断服务函数
    void USART1_IRQHandler()
    {
    	HAL_UART_IRQHandler(&usart1_handler);
    	//由于调用一次中断,进入中断回调函数后,中断就结束了,所以还要开启中断
    	HAL_UART_Receive_IT(&usart1_handler,rdata,sizeof(rdata));//使能接收中断
    }
    //编写接收完成中断回调函数
    void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
    {
    	u8 rec;
    	if(huart->Instance==USART1)
    	{
    		//rec = *((huart->pRxBuffPtr)-1);
    		rec = rdata[0];//保存接收到的数据
    		HAL_UART_Transmit(&usart1_handler,&rec,1,1000);
    	}
    }
    int main(void)
    {
      	Cache_Enable();                 //打开L1-Cache
      	HAL_Init();				        //初始化HAL库
      	Stm32_Clock_Init(432,25,2,9);   //设置时钟,216Mhz 
    	delay_init(216);
    	uart1_init();
        HAL_UART_Receive_IT(&usart1_handler,rdata,sizeof(rdata));//使能接收中断
    	while(1)
    	{
            
    	}
    
    }
    
    展开全文
  • STC15系列单片机双串口中断收发程序 **************************
  • 这又是一个半路开始的记录,此前已经实现了串口的固定字节长度通信,现在正在准备用最小系统板实现指定的串口通讯协议。 以上 串口通讯初始化及特殊功能寄存器设置: void UartInit() //串口初始化 { PCON |=...

    ❤2018.3.2

    这又是一个半路开始的记录,此前已经实现了串口的固定字节长度通信,现在正在准备用最小系统板实现指定的串口通讯协议。

    以上

    串口通讯初始化及特殊功能寄存器设置:

    void UartInit()	//串口初始化
    {
    
    
    	PCON |= 0x80;		//使能波特率倍速位SMOD
    	SCON  = 0x50;		//8位数据,可变波特率
    	AUXR &= 0xBF;		//定时器1时钟为Fosc/12,即12T
    	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
    	TMOD &= 0x0F;		//清除定时器1模式位
    	TMOD |= 0x20;		//设定定时器1为8位自动重装方式
    	TL1 = 0xFA;		//设定定时器初值 9600bps
    	TH1 = 0xFA;		//设定定时器重装值 9600bps
    	ET1 = 0;		//禁止定时器1中断
    	TR1 = 1;		//启动定时器1
    	
    	IE=0x00;		//禁止中断
    	IP=0x00;		//优先级清零
    	EA=1;			//开总中断
    	ES=1;			//开串口中断
    }

     

    ❤2018.3.3

     

    关于串口通讯协议我收到的大概是这样的格式

     

    格式: [协议头] [1字节(表示内容长度)] [内容] [协议尾]

    协议头 FF FF 00    协议尾 FB 01 FF 

    例:FF FF 00 05 CA 01 2C 02 58 FB 01 FF

    然后反馈并执行相应功能。

     

    关于串口中断函数我现在初步构想是这样的:

    这是个逻辑流程图,不是具体的实现流程,因为串口中断是每接收一个字节都会触发一次的,所以有些判断语句是贯穿始终的,这就需要不少的标量作为标记,如果都写在流程图里就很乱了,具体是怎样写我还没想好。

     

     

    ❤2018.3.6

    ○xdata可以将大数组保存到外部ram中,防止占用过多内存,这里可以摘一下相关文章。

     

    ❤2018.3.7

    疑问:

    ○中断能打断自己么?

        查了查资料,好像不行,同级别的中断不会被打断,只能被高级中断打断,同级别的中端会等中断函数执行结束之后再触发。(是这样的么?)

    ○怎么算中断函数执行结束?中断函数调用的函数还算不算中断函数?

    ○延时函数被中断打断,如何在中断结束后进入主函数?

    ○关于中断服务函数using的用法

    ○有时候有两种想法不知道用哪个好时可以都记录下来在应用的过程中很可能就想明白了,比如这次到底是声明一个新的变量表示正在接收数据还是用已有的标志变量最后发现还是得用个新的变量哈哈哈。

     

    ❤2018.3.10

    好烦,mdcsdn告诉我保存成功了结果之前打的都没了,还得再打一遍。

     

    ○昨天遇到的一个问题就是我的bReceiving标记只在串口数据接收第一个字节时置1,理论上在第一个字节接收结束时就应该被主循环的监测函数置0才对,但是实际情况是只要串口一直在接收数据,那么这个标记就一直保持1,我的推测是可能如果串口一直在接收数据则串口中断服务函数就一直处于激活状态而不会回到主循环。不过现在这个问题还不影响程序的功能,如果以后有影响的话我在考虑,现在先放着,或者以后有相关资料正是我的推测我再来补充,先码一个。

    ————好吧好吧,主要还是test里的延时1s惹的祸

     

    ○今天构思了一下T0定时器中断服务函数,功能如下:

    1、在串口数据接收超时时,自动将相关标记置0并将错误标记置1,;

    2、根据串口通讯协议,在录入过程中需要每秒发送一次反馈数据。

    流程图初步构想如下:

     

    ○串口中断服务程序经过一系列的修改之后功能已经基本稳定,目前的逻辑流程图如下:

    我只写了逻辑流程图,并没有写结构流程图(因为懒。。),流程图中省略了一些标记变量和清零等操作,总之大概是这么个意思。

    ○串口数据发送函数

    这个这个函数加入了串口发送超时退出,防止程序卡死,不过真的会发送超时么?

    void Send()		/*串口数据发送函数*/
    {
    	unsigned char i = 0;
    	unsigned char j = 0;
    	ES = 0;
    	for(i = 0; i < 8; i++)
    	{
    		SBUF = aFeedBackSample[i];
    		while(!TI)		//这个是实现串口数据发送超时退出,但是不报错,就是为了防止程序卡死
    		{
    			j++;
    			if(j > 10000)
    				break;
    		}
    		TI = 0;
    	}
    	aFeedBackSample[3] = 0x00;
    	aFeedBackSample[4] = 0x00;	
    	ES = 1;
    }

     

     

    ☆总结:

    截至2018.3.10基本实现了串口的接收和发送所需要的所有功能,接下来就是写对端口数据的解析,执行函数,还有一些应答函数,这个版本就到这里了,下面的版本会新建一个文件。


    总体来说过程还算顺利,虽然遇到一些小问题,但是还没碰到毫无思路这种情况
    其实这就是个小程序,只是我一直在拖延而已。。。
    我还没想好把程序分成几个文件之后怎么去控制版本的问题。。。或者这次就不做每个文件的版本控制了,以后遇到更复杂的程序再说吧,然后再参考参考其他现成的例子

     

    好了,over

     

    ❤2018.3.14

    补充:

    事情是这样的,我之前把串口接收超时报错的程序放在了主循环中,但是这样有一个问题:当键盘正在录入中时如果传来串口数据,那么在触发串口中断之后并不会回到主程序,于是串口接收超时检测并不会被触发,这样在录入过程中如果收到不正确的指令则不会报错也不会清空缓存,而后再接到正确指令后也不会正确响应,所以影响还是挺大的。于是我把原来放在主循环状态检测函数里的判断串口数据超时的语句放在了串口中断服务程序最后那里。

    但是我犯了一个错误,之前为了用一个定时器分别实现串口接收超时和录入过程中反馈两个功能,所以在每次调用函数时都进行了计时器赋初值,但是在将语句放入串口中断服务中后我以为初值不变的话每次启用都会自动重置,但是我想错了,TR和ET只是开启和关闭,并没有赋初值的功能,所以就造成了每接收一定的字符数后就会报错,经过排除确定是超时报警的问题,再一考虑才想起来是初值的问题。

    好了,先这样,有什么问题我再来补充。

     

    ❤2018.4.16

    今天整理了下串口通讯程序,把串口中断服务程序的结构流程图做了做,下面贴出来

    然后逻辑流程图也稍稍改了改

    总的来说没变,只是进行了调整。

     

    ❤2018.4.19

    之前记下来结果忘记了,指令解析函数要放在串口中断服务程序里,因为需要实现在敲击过程中能够执行停止指令,所以又修改了下流程图,如下:

    逻辑流程图:

    结构流程图:

    展开全文
  • 目录一、串口编程中struct termios结构体二、串口配置流程1、tcgetattr() 与 tcsetattr()控制终端3、cfsetispeed() 与 cfsetospeed()设置波特率   串口接口简称串口,也称串行通信接口(通常为COM接口),串行接口...


      串口接口简称串口,也称串行通信接口(通常为COM接口),串行接口( Serial Interface)是指数据一位一位地顺序传送,其特点是通信线路简单,只要一对传输线可实现双向通信,根据通信的方向可分为单工、半双工和全双工三种。在Linux 下标准的串口节点名为 /dev/ttyS* ,如果是USB转串口,则为/dev/ttyUSB*:

    在这里插入图片描述

    一、串口编程中struct termios结构体

      在串口编程中有一个很重要的结构体——struct termios,通过该结构体我们可对串口的属性(输入输出)进行控制:

    struct termios
    {
           tcflag_t c_iflag;           //输入模式标志
           tcflag_t c_oflag;           //输出模式标志
           tcflag_t c_cflag;           //控制模式标志
           tcflag_t c_lflag;           //本地模式标志
           cc_t    c_cc[NCCS];         //控制字符
    }
    

      其中tcflag_t定义为:

    typedef unsigned int tcflag_t
    

      在该结构体中c_cflag输入模式标志最为重要,可设置波特率、数据位、校验位、停止位。设置波特率需要在前加上B(B9600,B115200),然后对需要设置的位进行"与","或"操作,其中标志所代表的意义如下:

    • c_cflag控制模式标志
    位成员代表含义
    CBAUD波特率掩码位
    EXTA外部时钟
    EXTB外部时钟
    CSIZE数据位掩码位
    CSTOPB2位停止位
    CREAD接收使能
    PARENB奇偶校验位使能
    PARODD使用奇校验
    CLOCAL忽略终端状态行
    CRTSCTS硬件流控制使能位

    通常情况下CLOCAL和CREAD两个选项总是被打开,这两个选项可保证你的程序不会变成端口的所有者,而端口所有者需要去处理发散性控制和挂断信号,同时还保证串行接口驱动会读取输入的数据字节。

    • c_iflag输入模式标志
    位成员代表含义
    IGNBRK忽略BREAK键输入
    BRKINT如果设置了IGNBRK,BREAK键的输入将被忽略,如果设置了BRKINT ,将产生SIGINT中断
    IGNPAR忽略奇偶校验错误
    PARMRK标识奇偶校验错误
    INPCK允许输入奇偶校验
    ISTRIP去除字符的第8个比特
    INLCR将输入的NL(换行)转换成CR(回车)
    IGNCR忽略输入的回车
    ICRNL将输入的回车转化成换行(如果IGNCR未设置的情况下)
    IUCLC将输入的大写字符转换成小写字符(非POSIX)
    IXON允许输入时对XON/XOFF流进行控制
    IXANY输入任何字符将重启停止的输出
    IXOFF允许输入时对XON/XOFF流进行控制
    IMAXBEL当输入队列满的时候开始响铃,Linux在使用该参数而是认为该参数总是已经设置
    • c_oflag输出模式标志
    位成员代表含义
    OPOST处理后输出
    OLCUC将输入的小写字符转换成大写字符(非POSIX)
    ONLCR将输入的NL(换行)转换成CR(回车)及NL(换行)
    OCRNL将输入的CR(回车)转换成NL(换行)
    ONOCR第一行不输出回车符
    ONLRET不输出回车符
    OFILL发送填充字符以延迟终端输出
    OFDEL以ASCII码的DEL作为填充字符,如果未设置该参数,填充字符将是NUL(‘\0’)(非POSIX)
    NLDLY换行输出延时,可以取NL0(不延迟)或NL1(延迟0.1s)
    CRDLY回车延迟,取值范围为:CR0、CR1、CR2和 CR3
    TABDLY水平制表符输出延迟,取值范围为:TAB0、TAB1、TAB2和TAB3
    BSDLY空格输出延迟,可以取BS0或BS1
    VTDLY垂直制表符输出延迟,可以取VT0或VT1
    FFDLY换页延迟,可以取FF0或FF1
    • c_lflag本地模式标志
    位成员代表含义
    ISIG当输入INTR、QUIT、SUSP或DSUSP时,产生相应的信号
    ICANON使用标准输入模式
    ECHO显示输入字符
    ECHOE如果ICANON同时设置,ERASE将删除输入的字符,WERASE将删除输入的单词
    ECHOK如果ICANON同时设置,KILL将删除当前行
    ECHONL如果ICANON同时设置,即使ECHO没有设置依然显示换行符
    ECHOPRT如果ECHO和ICANON同时设置,将删除打印出的字符(非POSIX)
    TOSTOP向后台输出发送SIGTTOU信号

    二、使用串口流程

    1、打开串口

    comport->fd = open(comport->dev_name,O_RDWR|O_NOCTTY|O_NDELAY) ;
    

      openz函数除了普通参数外还有O_NOCTTY|O_NDELAY:

    • O_NOCTTY:通知Linux系统,这个程序不会成为这个端口的控制终端;
    • O_NDELAY:通知系统不管县DCD信号所线处的状态。

    2、串口配置流程

    a、tcgetattr() 与 tcsetattr()控制终端

    在这里插入图片描述
    tcgetattr()

    • 参数
      int fd:打开串口文件后,获取到的文件描述符;
      struct termios &termios_p: termios 类型的结构体,包含在 <termios.h> 头文件中,这里需要传地址或指针;

    • 功能:获取对应文件描述符相应串口的原始属性,保存在第二个参数中,通常获取串口需要对原始信息进行备份,在程序退出前需要修改回来,一边继续使用串口;

    • 返回值:成功返回0,失败返回-1。

    tcsetattr()

    • 参数
      int fd: 要设置属性的文件描述符
      int optional_actions: 设置属性时,可以控制属性生效的时刻,optional_actions可以取下面几个值:
      TCSANOW: 立即生效;
      TCADRAIN: 改变在所有写入fd 的输出都被传输后生效。这个函数应当用于修改影响输出的参数时使用。(当前输出完成时将值改变);
      TCSAFLUSH :改变在所有写入fd 引用的对象的输出都被传输后生效,所有已接受但未读入的输入都在改变发生前丢弃(同TCSADRAIN,但会舍弃当前所有值)。
      *termios termios_p: 用来设置的串口属性的结构体指针,对串口的termios配置好后,传入函数即可。

    • 功能:设置终端参数的函数;

    • 返回值:成功返回0,失败返回-1。
      在这里插入图片描述

    b、cfsetispeed() 与 cfsetospeed()设置波特率

    在这里插入图片描述
    在这里插入图片描述

    //函数原型
    static void set_baudrate (struct termios *opt, unsigned int baudrate)
    {
    	cfsetispeed(opt, baudrate);
    	cfsetospeed(opt, baudrate);
    }
    

    参数:

    • opt:通过结构体设置串口通信属性,这是指向该结构体的指针;
    • baudrate:串口没有内部时钟所以为异步通信,为了通信双方达到收发消息统一,需要设置通信双方的波特率相同。

    实现如下:

    int speed_arr[] = { B38400, B19200, B9600, B4800, B2400, B1200, B300,B38400, B19200, B9600, B4800, B2400, B1200, B300, };
    
    int name_arr[] = {38400, 19200, 9600, 4800, 2400, 1200, 300, 38400,19200, 9600, 4800, 2400, 1200, 300, };
    /* 设置波特率 */
    int set_baudrate(struct termios *opt,int baudrate)
    {
        int i;
        for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) {
            if(baudrate == name_arr[i])
            {
                if(cfsetispeed(opt,baudrate) < 0)
                {
                    printf("cfsetispeed failure:%s\n", strerror(errno));
                    return -1;
                }
    
                if(cfsetospeed(opt,baudrate) < 0)
                {
                    printf("cfsetospeed failure:%s\n", strerror(errno));
                    return -2;
                }
            }
        }
        return 0;
    }
    

    c、使用掩码设置数据位

    /* 设置数据位 */
    void set_databit(struct termios *opt,int databit)
    {
        opt->c_cflag |= (CLOCAL|CREAD ); //cLOCAL本地连接模式,CREAD开启串行数据接收
        opt->c_cflag &= ~CSIZE; //字符长度,取值范围为CS5、CS6、CS7或CS8
        switch(databit){
            case 5:
                opt->c_cflag |= CS5;
                break;
            case 6:
                opt->c_cflag |= CS6;
                break;
            case 7:
                opt->c_cflag |= CS6;
                break;
            case 8:
                opt->c_cflag |= CS8;
                break;
            default:
                opt->c_cflag |= CS8;
                break;
        }
    
    }
    

    d、使用c_cflag和c_iflag设置奇偶校验

    /* 设置校验位 */
    void set_parity(struct termios *opt,char parity)
    {
        switch(parity){
            case 'n':
            case 'N':
                 opt->c_cflag &= ~PARENB; //使用奇偶校验
                 break;
            case 'e':
            case 'E':
                 opt->c_cflag |= PARENB;
                 opt->c_cflag &= ~PARODD;   //对输入使用奇偶校验,对输出使用偶校验
                 opt->c_cflag |= (INPCK | ISTRIP); //允许输入奇偶校验|去除字符第8比特
                 break;
            case 'o':
            case 'O':
                 opt->c_cflag |= (PARENB | PARODD); //使用输出奇偶校验
                  opt->c_cflag |= (INPCK | ISTRIP); //              允许输入奇偶校验|去除字符第8比特
                  break;
            default:
                  opt->c_cflag &= ~PARENB; //默认使用奇偶校验
                  break;
        }
    }
    

    e、设置停止位

    /* 设置停止位 */
    void set_stopbit(struct termios *opt, int stopbit)
    {
        switch(stopbit)
        {
            case 2:
                opt->c_cflag |= CSTOPB;  //设置两个停止位
                break;
            default:
                opt->c_cflag &= ~CSTOPB;  //停止位为1,则要清楚CSTOPB
                break;
        }
    }
    
    

    f、设置最少字符和等待时间

      对于接收字符和等待时间没有特别要求时可设为0:

        //串口超时设置
        options.c_cc[VMIN] = 0;
        options.c_cc[VTIME] = 0;
    

    3、读写数据

      写数据使用write系统调用,成功时会返回写入的字节数,失败时会返回-1,例如:

    rv = write(fd, buf, buf_size);
    if (rv < 0)
    	printf("write data failed!\n", strerror(errno));
    

      读串口数据我们需要考虑到一个问题就是timeout超时问题,当端口在raw data mode操作模式下,那么read系统调用将返回从串口输入缓冲区中实际得到的字节数,如果没有数据可读,那么该系统调用将会被阻塞(block)直到有数据为止,如果超过一定时间仍然没有数据可读,那么将返回一个错误(读错误)。

    rv = read(comport->fd, buf, buf_size);
        if(rv < 0)
        {
            printf("Read data from dev failure:%s\n", strerror(errno));
            return rv;
        }
    

      我们也可通过fcntl()函数使read()
    没有数据可读的情况下立即返回而不是被阻塞:

    fcntl(fd, F_SETFL, FNDELAY);
    //FNDELAY选项在read无数据可读立即返回0,实际调用如下:
    fcntl(fd, F_SETFL, 0);
    

    4、关闭串口

      关闭串口就是关闭该串口下的文件描述符:

    close(comport->fd);
    
    展开全文
  • 串口流程图1

    2011-08-13 14:58:00
    操作串口主要分为:初始化串口、读串口、写串口。 其中,读串口需要使用线程。 一、初始化串口 在使用串口的时候,我们需要配置串口相关的参数比如,串口号,波特率,数据位,停止位等等。 首先,如果...
  • 关于串口通信原理方面的文章: 嵌入式stm32 复习(工作用)— ...先上完整串口收发部分代码!!! #include "usart1.h" #include "stdio.h" #include "string.h" #define CR1_OVER8_Set ((u16)0x8000) u16 USA...
  • 串口收发测试

    2020-01-16 17:33:29
    https://www.cnblogs.com/jiangjh/p/8690475.html
  • 在进行PID参数整定的工作过程中,我需要将电机的转速、扭矩、母线电压、母线电流、相电压...目前整个流程已经走通,在此将实现过程中遇到的问题,解决方法,以及尚未解决的疑问进行总结。首先声明本人是一个初学Mat...
  • #QT串口助手设计流程(如何实现一个串口助手 索引一、程序设计流程二、基础配置三、涵盖知识点四、参考博文&完整例程 一、程序设计流程 在做好ui界面后,整个程序的设计就如注释中的几个步骤(捕获端口、创建...
  • 1.dma发送流程1.配置DMA发送中断 - NVIC_Init2.配置串口中断 - NVIC_Init3.GPIO配置 - GPIO_Init4.DMA...串口参数初始化 - USART_Init2.dma接收流程1.配置串口中断 - NVIC_Init2.GPIO配置 - GPIO_Init3.DMA接收配...
  • QT-串口基本流程

    2020-11-05 17:30:35
    添加串口库 QT += core gui serialport 添加必要头文件 #include <QSerialPort> //提供访问串口的功能 #include <QSerialPortInfo> //提供系统中存在的串口的信息 初始化串口对象 //创建串口对象 ...
  • python实现串口收发

    万次阅读 2020-06-30 12:47:04
    python 实现串口通信 1. python 安装在vscode中运行 参考 搭建环境 . 官网下载 安装 python-3.8.0-amd64.exe。 用 python 解释器: 使用Ctrl+Shift+P打开命令板,输入Python: Select Interpreter进行搜索。 提示安装...
  • 单片机串口通信程序的流程方案

    千次阅读 2019-09-21 10:51:42
    理论上,串口通信的收发数据缓冲区如果大于2字节,那么就可以间隔更长时间去取数或发数。但是,如果一个任务的处理时间超过最大时间还是会丢数! 对于最基本的PIC系列单片机,最大时钟是20MHz,指令周期是200ns,...
  • 4.6串口数据收发实验 4.6.1实验目的 1.了解串口通信的相关知识; 2.学习CC2530单片机串口相关寄存器配置,实现串口通信功能; 4.6.2 实验讲解 CC2530芯片有两个串行接口UART0和UART1: UART0对应RXD(P02)、...
  • 用Qt 5写一个串口收发桌面工具

    千次阅读 2020-12-01 15:27:13
    今天用Qt写了一个串口收发工具,记录下整个流程。 1、项目工程布局 2、ui文件布局 3、widget.h文件 #ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QtSerialPort/QSerialPort&...
  • ZStack版本:ZStack-CC2530-2.5.1a 下载和调试器:SmartRF04EB IDE开发软件:IAR Embedded Workbench IDE - 8051 10.20.1 开发平台:基于TI-CC2530的任意厂家的...2、从上位机给CC2530串口发送信息,CC2530收到信息 ...
  • 串口接收数据有误,求指导!

    千次阅读 2018-11-19 17:53:09
    上位机给串口发送数据,单片机通过串口接收到的数据以什么结尾@TOC 串口接收到数据后对数据最后几位进行判断,总是进不去判断函数是什么原因,串口接收到数据后会不会自动加什么标志,求大佬指导? 串口通过中断...
  • 用Verilog写一个串口接收程序

    千次阅读 2019-07-12 16:02:26
    用Verilog写一个串口接收程序欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段...丰富你的文章UML 图表FLowchart流程图导出与导入导出导入...
  • 单片机初学者,经常在双机通信这一块,遇到困难,我将我之前遇到的困难整理了一下,发给大家,具体的描述,在我的另一片帖子中有详细描述,这里只放了发送函数工程。
  • 转载于:https://www.cnblogs.com/CodeWorkerLiMing/p/11296070.html
  • 串口驱动流程分析

    千次阅读 2016-09-30 17:00:06
    TTY驱动程序架构 TTY概念解析 TTY架构分析 ...串口终端是使用计算机串口连接的终端设备。Linux把每个串行端口都看作是一个字符设备。这些串行 端口所对应的设备名称是/dev/ttySAC0;/dev/ttySAC1……
  • Linux下实现串口接收GPS数据

    千次阅读 2019-08-13 12:35:24
    最近在做Linux下的串口接收并处理GPS数据,那对于是新手的我来说,就将这个项目分成两步,第一,接收数据,第二,处理数据。本文注重第二步的代码实现,第一步只会简单提及。本文使用的嵌入式开发板龙芯智龙1C,GPS...
  • 工作流程:AD7818采样模拟信号,12bits输出,串口将数据发送给PC。串口发送波特率57600Bd,数据位8位,停止位一位。每个数据分两次发送,高四位补零。设计GUI界面接收串口数据并显示波形。GUI界面如下:功能描述:1....
  • 读入数据总结UML 图表FLowchart流程图导出与导入导出导入 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下...
  • 随着人类社会的发展,利用计算机设备实现生产过程的自动化成为提高生产力、减轻 劳动强度的有效手段。由于大量设备的使用,必须随时了解实际情况,因此要对实时工作进行 监视,并通过计算机辅助...和串口通信过程。
  • STM32L4的串口打印程序欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左...
  • 关于使用STM32的HAL库通过串口收发大量数据时串口接受失效的解决办法欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个...
  • 51 单片机串口通信程序,RS232串口通信 含详细例子。 含详细例子,RS232串口通信单片机接收发送数据的 C51程序,手把手教你用增强型51 实验板实现RS232 串口通信 51串口通信

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 11,132
精华内容 4,452
关键字:

串口收发流程图