UART串口编程

来源:互联网 发布:seo整站优化多少费用 编辑:程序博客网 时间:2024/06/17 01:05
        基础知识:
        1.波特率:每秒传输的二进制位数,bps。
        2.UART用的是标准TTL/CMOS逻辑电平,可以通过MAX3232转换成RS-232逻辑电平。RxD/TxD数据线以位为最小数据传输单位。
        3.帧:有效传输单位,具有完整数据意义。里面包含:起始位,数据位,校验位,停止位。一帧数据可以有5-8个数据位,从最低位开始传输,传输前约定好传输的格式和波特率。所以能达到发送和接受的数据同步。
        4.奇偶校验:所有数据位中包含1的个数。
        5.帧格式:n个停止位+起始位+(低)数据位(高)+奇偶校验位+n个停止位。。。帧的分割是有起始位来标志的。
        6.UART工作流程:
        发送数据:CPU----》FIFO-------》发送移位寄存器---------》TxD数据线
        CPU将数据通过总线发送到FIFO中,UART将FIFO中的数据复制到发送移位寄存器中。发送移位寄存器根据传输格式(添加开始位,数据位,校验位,中止位)一位一位的发送到TxD数据线上发射。
        接受数据:RxD数据线--------》接受移位寄存器-----》FIFO----------》CPU
        接受移位把RxD数据线上的数据一位一位接受过来,然后复制到FIFO中,CPU就可以访问到FIFO中数据了。
        7.硬件控制流:这个可以联系到TCP三次握手,当要发送数据时,要等待接受方准备好,并返回个准备好的信号。当发送方接受到这个信号,才开始发送数据。
     
        只有当nCTS接受到信号后TxD才会发送数据。
        8.设置波特率除数因子UBRDIV0。公式:UBRDIVn = (int)((Uart Clock)/(baud)/16) -1; Uart Clock:UART时钟频率。 baud:波特率。一般程序中公式将演变成:rUBRDIV0=( (int)(pclk/16./baud+0.5) -1 );./ 为点除,因为pclk/16后为整数,所以点除得到float。+0.5 则是为强转时能够取到整数,因为c语言中强转是直接舍弃小数部分,而该公式要求四舍五入。
      如:baud为115200bps 且UART时钟频率为40MHz。
      UBRDIVn = (int)(pclk/16./baud+0.5) -1
                   = (int)22.2-1
                   = 21
     9.UART线性控制寄存器:设置传输格式,即是帧格式
        
         10.设置UCON寄存器,设置数据访问的方式:中断,轮询,DMA。以及时钟分频,为波特率选择时钟频率。
        
        
        11.是否使用FIFO控制寄存器,这里使用了非FIFO模式,就不贴寄存器设置图片了。
        12.UTRSTAT0寄存器,相当于一个状态寄存器,实时监控UART是否有数据发来或者数据是否发送完毕。
        
        13.UTXH0发送数据寄存器,URXH0接受数据寄存器。
       
        
         14.还要设置下IO端口,以及上拉电阻之类的。
        
         
         代码部分
       
 #include<stdio.h>        #include<stdarg.h>        #define rULCON0   (*(volatile unsigned int*)0x50000000)  //uart 0设置传输格式        #define rUCON0    (*(volatile unsigned int*)0x50000004)  //设置时钟源,访问方式        #define rUFCON0   (*(volatile unsigned int*)0x50000008)  //FIFO寄存器        #define rUMCON0   (*(volatile unsigned int*)0x5000000c)  //硬件控制流        #define rUTRSTAT0 (*(volatile unsigned int*)0x50000010) //检测是否发生/接受完毕        #define rUERSTAT0 (*(volatile unsigned int*)0x50000014) //错误状态寄存器        #define rUFSTAT0  (*(volatile unsigned int*)0x50000018) //FIFO状态寄存器        #define rUFASTAT0 (*(volatile unsigned int*)0x5000001c) //Modem状态寄存器        #define rUTXH0    (*(volatile unsigned int*)0x50000020) //发生缓存寄存器        #define rURXH0    (*(volatile unsigned int*)0x50000024) //接受缓存寄存器        #define rUBRDIV0  (*(volatile unsigned int*)0x50000028)//UART 0 Baud rate divisor        #define rGPHCON   (*(volatile unsigned int*)0x56000070) //RxD/TxD控制        #define rGPHDAT   (*(volatile unsigned int*)0x56000074) //RxD数据控制        #define rGPHUP    (*(volatile unsigned int*)0x56000078) //RxD上拉电阻       //#define rUTXH0 (*(volatile unsigned char *)0x50000020)//UART 0 Transmission Hold       //#define rURXH0 (*(volatile unsigned char *)0x50000024)//UART 0 Receive buffer       #define WrUTXH0(ch) (*(volatile unsigned char *)0x50000020)=(unsigned char)(ch)       #define RdURXH0()   (*(volatile unsigned char *)0x50000024)       #definte uint32 unsigned int        #define uint8 unsigned char        //定义串口传输格式        typedef struct UartMode{        uint8 dateLen;//date length 5/6/7/8        uint8 stopLen;//stop bite 1/2        uint8 parity; //parity  0==no parity 1==odd parity  2==even parity        }UartMode;        static uint32 UartNum = 0;         //做下前置声明         void Uart_Port_Init(int UartNum);         int Uart_init(UartMode mode,uint32 baud,uint32 pclk,uint32 UartNum);         char Uart_ReceviceCh(void);         void Uart_ReceviceString(char *string);         void Uart_SendCh(char ch);         void Uart_SendString1(char * string);        //延迟程序         void Delay(uint32 time)         {             uint32 i = 0;             if (0==time)             time = 400;               for(;time > 0;time--){                   for(;i < 3000;i++) ;             }         }        //串口端口初始化        void Uart_Port_Init(int UartNum)        {           rGPHCON = rGPHCON & (~(0xffff));    //置零           if (0 == UartNum)  {              rGPHCON = rGPHCON | (10 << 4);   //设置为RxD[0] TxD[0]           }else if(1 == UartNum)  {             rGPHCON = rGPHCON | (10 << 8);   //设置为RxD[1]  TxD[1]          } else              rGPHCON = rGPHCON | (10 << 12);  //设置为RxD[2]  TxD[2]             rGPHUP = 0x0;                     //不用上拉电阻        }        //串口初始化,传输格式,波特率,硬件控制流等       int Uart_Init(UartMode mode,uint32 baud,uint32 pclk,uint32 UartNum)       {          uint32 allMode; //先把所有模式设置好,然后一次性写入寄存器          //首先判断设置的传输的格式是否正确          if ((mode.dateLen < 5)||(mode.dateLen > 8)){               return 0;           }           if ((mode.stopLen < 1) || (mode.stopLen > 2)){               return 0;             }          if ((mode.parity < 0) || (mode.parity > 2)){              return 0;          }         //判断波特率是否正确         if ((0 == baud) || (baud >115200)){            return 0;         }         //下面是正式初始化串口了,这里假设是串口0,不再判断了         //设置工作模式和传输格式         allMode =  0; //设置正常模式,红外线接收设置1             //设置奇偶校验         if (0 != mode.parity)    {            mode.parity = mode.parity + 3;            allMode = ((allMode | mode.parity) << 2);           }         //设置停止位          mode.stopLen = mode.stopLen - 1;          allMode = ((allMode | mode.stopLen) << 1);        //设置数据位          mode.dateLen = mode.dateLen - 5;          allMode = allMode | mode.dateLen;          rULCON0 = allMode;         //设置串口波特率,即是设置波特率除数因子寄存器          rUBRDIV0 = ((int)(pclk/16./baud+0.5)-1);          rUFCON0 = 0x0 ;//非FIFO          rUMCON0 = 0x0 ;//非硬件控制流模式          rUCON0 = 0x805;//使用中断或者轮询模式访问数据          Delay(5);        }        //接收一个字符        char Uart_ReceviceCh(void)        {           //不判断串口号UartNum           while(!(rUTRSTAT0 & 0x1));//循环查看数据是否到来,这里有阻塞,可以用if判断           return RdURXH0();        }        //接收字符串       void Uart_ReceviceString(char *string)        {           //如果这里不进行串口初始化,那在主函数调用本函数前就要初始化           char *string2 = string;           char ch;           //以换行字符为标志,只接受一行字符串           while((ch = ReceviceCH())!= '\r') {           //退格符           if (ch == '\b'){            //先判断下是否是首字母退格,把地址转换为int型才能比较大小            //如果相等,则不能退格            if ((int)string2 < (int)string)  {            Uart_printf("\b \b");            string--;//后退一个字符           }         }else{            *string++ = ch;            Uart_SendCh(ch);           }         }            *string = '\0';//字符串接受标志             Uart_SendCh('\n');//接受完毕,补充一个回车键         }         //发送字符         void Uart_SendCh(char ch)       {           //不判断串口号,直接默认为串口0           //如果是换行符,发送一个回车键           if (ch == '\n')   {           while(!(rUTRSTAT0 & 0x2));//循环等待发送缓存为空           WrUTXH0('\r');//发送回车符        }          while(!(rUTRSTAT0 & 0x2));          Delay(10);          WrUTXH0(ch);//发送字符        }        //接收字符串        void Uart_SendString(char * string)       {          while(*string)          Uart_SendCh(*string++);       }       //格式化打印      void Uart_Printf(char *fmt,...)      {         va_list ap;//可变参数列表         char string[256];         va_start(ap,fmt);         vsprintf(string,fmt,ap);         Uart_SendString(string);         va_end(ap);      }

0 0
原创粉丝点击