• 【嵌入式学习】--Uart串口


    在这里插入图片描述
    下面是9针串口的各个引脚
    在这里插入图片描述

    串口通信时序图

    一组数据是由起始位+数据位+奇偶校验位+停止位组成。

    起始位
    下降沿信号触发,表示数据开始传输。

    数据位
    有5~8位,一般采用8位,因为我们平时传输的英文字符,是使用8bit的字节来进行ascall码表示的。

    奇偶校验位

    如果数据中的“1”的总数为奇数个,那么就是奇校验。
    如果数据中的“1”的总数为偶数个,那么就是偶校验。

    停止位
    一般有1、1.5、2位表示,一般使用1位。

    源码

    以stm32f103c8t6为例
    实际上是利用USART_SendData()这个函数进行按字节发送。和USART_GetITStatus()函数判断接收中断位是否发生改变来进行接收数据。

    uart.c

    #include "uart.h"
    
    void uart_config(void)
    {
    		/* GPIO端口设置 */
    		USART_InitTypeDef USART_InitStructure = {0};
    		NVIC_InitTypeDef	NVIC_InitStructure = {0};
    		GPIO_InitTypeDef  GPIO_InitStructure = {0};
    		
    		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    		RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
    	
    		/* PA2 TXD2 */
    		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 
    		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
    		GPIO_Init(GPIOA, &GPIO_InitStructure);
    		 
    		/* PA3 RXD2 */
    		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; 
    		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; 
    		GPIO_Init(GPIOA, &GPIO_InitStructure);
    		
    		/* Usart2 NVIC 配置 */
    		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);/* 嵌套向量中断控制器组选择 2位抢占 2位响应*/
    		
    		NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; /* 抢占优先级3 */
    		NVIC_InitStructure.NVIC_IRQChannelSubPriority	= 2;        /* 响应优先级2 */
    		NVIC_InitStructure.NVIC_IRQChannelCmd	= ENABLE;        /* IRQ通道使能 */
    		NVIC_Init( &NVIC_InitStructure );                      /* 根据指定的参数初始化NVIC寄存器 */
    	
    		/* USART 初始化设置 */
    		USART_InitStructure.USART_BaudRate = 115200; //设置波特率;
    		USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    		USART_InitStructure.USART_StopBits = USART_StopBits_1; //1位停止位
    		USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位
    		USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
    		USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收发模式
    		USART_Init(USART2, &USART_InitStructure); 
    		
    		/* 开启中断 */
    		USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启接收中断
    		//USART_ClearFlag(USART2,USART_FLAG_TC);
    		USART_Cmd(USART2, ENABLE);//使能串口
    }
    
    void usart2_send_byte(u8 data)
    {
    	while(!USART_GetFlagStatus(USART2,USART_FLAG_TXE)){}
    	USART_SendData(USART2,data);
    }
    
    
    void USART2_IRQHandler(void)
    {
    		u8 res=0;
    		
        if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
        {
    				//led_turn();
            res = USART_ReceiveData( USART2 );                      
    				//USART_SendData(USART2,res);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    51单片机
    实际上是将数据放入SBUF中,然后等待TI状态位改变,进行发送。判断RI状态位是否改变来获取数据输入。

    #include 
    #include "uart.h"
    
    #define uint unsigned int
    #define uchar unsigned char
    typedef unsigned int u16;	  //对数据类型进行声明定义
    typedef unsigned char u8;
    
    //串口初始化函数  9600
    void URATinit()
    {
     TMOD=0x20;
     SCON=0x50;
     TR1=1;
     TH1=0xfd;
     TL1=0xfd;
     EA=1;
     ES=1;
    }
    
    //发送一个字符
    void Uart_Send_Byte(unsigned char dat)
    {
     	SBUF = dat;
    	while(!TI);
    	TI=0;
    }
    
    u8 ch,i;
    u8 RX_BUF[10],RX_DAT[10],RX_CNT=0,RX_OVER=0;
    //串口接收中断
    void Uart_IRQ() interrupt 4
    {
     /*if(RI)
     {  
       RI=0;//清标志位 
       ch=SBUF;
       if(ch=='A') {}
     } */
     if(RI)
     {  
       ch=SBUF;
       if(ch!='}')
       {
    	  RX_BUF[RX_CNT++]=ch;
       }
       else	//结束
       {
    	 for(i=0;i<RX_CNT;i++)
    	 {
    	  	RX_DAT[i]=RX_BUF[i];
    	 }
    	 
    	 RX_CNT=0;
    	 RX_OVER=1;
       }
       RI=0;//清标志位 
     } 	 
    }
    
    
     //重写putchar函数
     char putchar(char c)
     {
         Uart_Send_Byte(c);
         return c;
     }
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    RS232与RS485的区别

    1)RS232
    对于TTL电平:3.3V或者5V为高电平,0V为低电平。这样的缺点就是容易失真,也导致了采用TTL电平的普通串口的有效传输距离不远。
    RS232电平:3V-15V为高电平-15V-3V为低电平。为全双工通信模式。

    (2)RS485
    RS485为一般半双工通信模式(也可全双工),使用差分信号。
    RS485差分线路包括2个信号:
    线路A(TX+/RX+、D+):非方向信号
    线路B(TX-/RX-、D-):反向信号

    表示0和1:
    若是SPACE(逻辑0),线路A信号电压比线路B高
    若是MARK(逻辑1),线路B电压比线路A高

    当一个总线上需要多个主机/从机时,使用RS485更合适,一般用于自动化工厂。

  • 相关阅读:
    Docker 使用手册
    Java——jdk8新特性、Lambda表达式、Stream流
    STM32 I2C详解
    最长的可整合子数组的长度
    elasticsearch
    2023秋招大厂经典面试题及答案整理归纳(341-360)校招必看【Linux篇】
    刨根问底:为什么玩游戏会让手机变得更热?
    安卓APP(1)——安卓工程构建和第一APP运行
    PHP8的类与对象的基本操作之成员变量-PHP8知识详解
    springboot集成mongoDB高级聚合查询,关联查询
  • 原文地址:https://blog.csdn.net/weixin_46020788/article/details/126161486