你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

直接寄存器操作实现统一串口初始化(在PZ-6806L验证通过)

[复制链接]
aiherong 发布时间:2018-12-3 11:19
//-------------------------- AHR_USART.C --------------------------------------------------------------
#include "AHR_USART.H"
u8  COMBUF[256]="0";    //接收缓冲,最大256个字节
u8  iComBuf=0;
u8  ComNow =2;          // 为区分5个串口共用一个缓冲区的识别问题而作的标记,显示时用颜色区分
//=====================================================================================================
// 直接寄存器操作实现全部串口通信初始化及数据收发:如:US123ART45Init(3,9600,0x0C,2,0,0,0,0);串3优先级2
//      TX-串口输出: 1-A9 ;2-A2;3-B10;4-C10;5-C12  //char str[]="4Step:1.RCC;2.AFIO;3.USART;4.NVIC";
//      RX-串口输入: 1-A10;2-A3;3-B11;4-C11;5-D2            未完成:NVIC 仍然使用库函数  -- 20180728 --
//-----------------------------------------------------------------------------------------------------
const u32 irqNOADcom[5]={37/*0xD4:COM1*/,38/*0xD8:COM2*/,39/*0xDC:3*/,52/*0x110:4*/,53/*0x114:5*/};
const u32 APB2IO_APB1US23ART45[10]={0x4004,0,0x04,0x20000,0x08,0x40000,0x10,0x80000,0x30,0x100000};
const u32 USART_REGADDR[5]={0x40013800,0x40004400,0x40004800,0x40004C00,0x40005000};
const u32 COMxBaudRate[4]={0xEA6/*9600*/,0x271/*57600*/,0x138/*115200*/,0x08C/*256000*/};
const u32 TXRX_PortSet[5][6]={{0x40010804,0x000000B0,0xFFFFFFBF,0x40010804,0x00000400,0xFFFFF4FF},
                               {0x40010800,0x00000B00,0xFFFFFBFF,0x40010800,0x00004000,0xFFFF4FFF},
                               {0x40010C04,0x00000B00,0xFFFFFBFF,0x40010C04,0x00004000,0xFFFF4FFF},
                               {0x40011004,0x00000B00,0xFFFFFBFF,0x40011004,0x00004000,0xFFFF4FFF},
                               {0x40011004,0x000B0000,0xFFFBFFFF,0x40011400,0x00000400,0xFFFFF4FF}};
void US123ART45Init(u8 iCOM,u32 baudRate,u8 Tx8Rx4,u8 priPS,u8 Ds1908,u8 St0115,u8 y1n0CRC,u8 HFr1c2)
{
    NVIC_InitTypeDef structNVIC;         //irqNOADcom[0]=USART1_IRQn; priPS-主副优先级级别(暂定相同)
    uint32_t tmpReg=0; //参数Ds1908=1:数据9位,=0:8位;St011522315=0,1,2,3;停止位=1,0.5, 2, 1.5
    *(volatile unsigned long *)(0x40021018)|=APB2IO_APB1US23ART45[iCOM*2-2]; //打开  GPIOX 时钟
    *(volatile unsigned long *)(0x4002101C)|=APB2IO_APB1US23ART45[iCOM*2-1]; //打开U(S)ARTX时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);  //所有涉及中断必须开放此时钟(外中断皆复用端口)
    *(volatile unsigned long *)TXRX_PortSet[iCOM-1][0]|=TXRX_PortSet[iCOM-1][1]; // TX
    *(volatile unsigned long *)TXRX_PortSet[iCOM-1][0]&=TXRX_PortSet[iCOM-1][2];
    *(volatile unsigned long *)TXRX_PortSet[iCOM-1][3]|=TXRX_PortSet[iCOM-1][4]; // RX
    *(volatile unsigned long *)TXRX_PortSet[iCOM-1][3]&=TXRX_PortSet[iCOM-1][5];
    tmpReg = *(volatile unsigned long *)(USART_REGADDR[iCOM-1]+0x10);     // 设置 USART_CR2
                                  //--.LINEN.STOP[1:0],CLKEN.CPOL.CPHA.LBCL,--.LBDIE.LBDL.--,ADD[3:0]
        tmpReg&=(uint16_t)0xCFFF; // 1  1     0    0  , 1     1    1    1  ,1   1  .... 1   //清STOP
        if (St0115 != 0) tmpReg |= (St0115 << 12);          // 停止位设置0-1;1-.5;2-2
    *(volatile unsigned long *)(USART_REGADDR[iCOM-1]+0x10) = tmpReg;     // 将设置写回寄存器CR2
    tmpReg = *(volatile unsigned long *)(USART_REGADDR[iCOM-1]+0x0C);     // 设置 USART_CR1
                        // UE M,WAKE PCE PS PEIE,TXEIE TCIE RXNEIE IDLEIE,TE RE RWU SBK
        tmpReg&=0xE9F3; // 1  0,  1   0  0   1  ,  1    1      1     1   , 0  0   1   1  // 清M等位
        if (Ds1908 != 0) tmpReg |=0x00001000;              //数据位9位; 缺省 Ds1908=0数据位8位
        if (y1n0CRC!= 0) tmpReg |=0x00000400;              //偶校验   ; 缺省y1n0CRC=0不校验
        if (Tx8Rx4 != 0) tmpReg |=Tx8Rx4;                  //8-使能Tx模式;4-使能Rx模式;0xC-TxRx全能
    *(volatile unsigned long *)(USART_REGADDR[iCOM-1]+0x0C) = tmpReg;     // 将设置写回寄存器CR1
    tmpReg = *(volatile unsigned long *)(USART_REGADDR[iCOM-1]+0x14);     // 设置 USART_CR3
                        // CTSIE CTSE RTSE,DMAT DMAR SCEN NACK,HDSEL IRLP IREN EIE
        tmpReg&=0xFCFF; //  1     0    0  , 1    1    1    1  , 1     1    1    1  //清CTSE/RTSE
        if (HFr1c2 != 0) tmpReg |= (HFr1c2 << 8); //HFr1c2 =0-禁止;1-RTS/2-CTS/3-R&CTS硬件流控制使能
    *(volatile unsigned long *)(USART_REGADDR[iCOM-1]+0x14) = tmpReg;     // 将设置写回寄存器CR3
    switch (baudRate){  //tmpReg = *(volatile unsigned long *)(USART_REGADDR[iCOM-1]+0x08);
        case  57600: tmpReg = COMxBaudRate[1]; break;  // ^--与下面sprintf()语句结合直接读波特率16进制
        case 115200: tmpReg = COMxBaudRate[2]; break;  // 如果计算则用到下面两句:
        case 256000: tmpReg = COMxBaudRate[3]; break;  //tmpReg = (u32)Mantissa <<4; //高12位-整数部分
        case   9600:                           //tmpReg |= (0x0000000F & Fraction); // 低 4位-小数部分
        default:     tmpReg = COMxBaudRate[0]; break;   // v--形成数组再经switch查询,写回波特率寄存器
    }           //sprintf(str,"baudRate:%8X",tmpReg); LCD_ShowString(10,160,240,180,16,(u8*)str);
    *(volatile unsigned long *)(USART_REGADDR[iCOM-1]+0x08) = tmpReg;     // 将波特率写入寄存器
    *(volatile unsigned long *)(USART_REGADDR[iCOM-1]+0x0C) |=0x00002000; //使能串口
    *(volatile unsigned long *)(USART_REGADDR[iCOM-1]+0x00) &=0xFFFFFFBF; //清除中断标志
    *(volatile unsigned long *)(USART_REGADDR[iCOM-1]+0x0C) |=0x00000020; //使能串口接收缓冲非空中断
    structNVIC.NVIC_IRQChannel =  irqNOADcom[iCOM-1];   // 串口中断通道
    structNVIC.NVIC_IRQChannelPreemptionPriority = priPS;   // 不能相同      //抢占优先级
    structNVIC.NVIC_IRQChannelSubPriority        = priPS;   // 不能相同      //子优先级
    structNVIC.NVIC_IRQChannelCmd                = ENABLE;               //IRQ通道使能
    NVIC_Init(&structNVIC);                                          //根据指定参数初始化VIC寄存器
}
void USART2_IRQHandler(void) {      //串口2中断服务程序, switch语句专用于格式化以回车换行结束的ASCii串
    u8 r=0;
    static u8 i=0;
    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) {  //接收中断
if(ComNow!=2) ComNow=2;
        r=USART_ReceiveData(USART2);  //读串2到全局数组
        switch (r){
            case 0x0A: iComBuf=i; i=0; break;
            case 0x0D: USART_ClearITPendingBit(USART2,USART_IT_RXNE);  break;
            default:    COMBUF[i]=r; i++; i&=0xFF; break;    // 限制在0~255之间
        }
    }
    if (USART_GetFlagStatus(USART2,USART_FLAG_ORE)==SET)     //溢出则必须清零
       { USART_ClearFlag(USART2, USART_FLAG_ORE); USART_ReceiveData(USART2); }
}
void UART5_IRQHandler(void) {                                // 串口5中断服务程序
    if(USART_GetITStatus(UART5, USART_IT_RXNE) != RESET) {
        USART_ClearITPendingBit(UART5,USART_IT_RXNE);        //清除接收中断标志
if(ComNow!=5) ComNow=5;
        COMBUF[iComBuf]=USART_ReceiveData(UART5);
        iComBuf++; iComBuf&=0xFF;                            // 限制在0~255之间
    } USART_ClearFlag(UART5,USART_FLAG_TC);
}
void UART4_IRQHandler(void) {                                // 串口4中断服务程序
    if(USART_GetITStatus(UART4, USART_IT_RXNE) != RESET) {
        USART_ClearITPendingBit(UART4,USART_IT_RXNE);         
if(ComNow!=4) ComNow=4;
        COMBUF[iComBuf]=USART_ReceiveData(UART4);            //读串2到全局数组
        iComBuf++; iComBuf&=0xFF;                            // 限制在0~255之间
    } USART_ClearFlag(UART4,USART_FLAG_TC);
}
void USART3_IRQHandler(void) {                                // 串口3中断服务程序
    if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) {
        USART_ClearITPendingBit(USART3,USART_IT_RXNE);        
if(ComNow!=3) ComNow=3;
        COMBUF[iComBuf]=USART_ReceiveData(USART3);            //读串3到全局数组
        iComBuf++; iComBuf&=0xFF;
    } USART_ClearFlag(USART3,USART_FLAG_TC);
}
void USART1_IRQHandler(void) {           // 串口1中断服务程序,收到后随即发出去(为普中开发板而暂时保留)
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){  //接收中断
        COMBUF[255] = USART_ReceiveData(USART1);
        USART_SendData(USART1, COMBUF[255]); while(USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET);
    } USART_ClearFlag(USART1,USART_FLAG_TC);
}
struct __FILE { int handle; }; FILE __stdout; // 标准库需要的支持函数
_sys_exit(int x)   { x = x; }  // 定义_sys_exit()以避免使用半主机模式
int fputc(int ch,FILE *p) {    // 默认函数在使用 printf函数时自动调用
      USART_SendData(USART1,(u8)ch);while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);return ch;
}
//-------------------------------------------- end of AHR_USART.C -------------------------------------
//---------------- AHR_USART.H ------------------------------------------------------------------------
#ifndef __usart_H
#define __usart_H
#include "aiherong.h"
extern u8 iComBuf;            // 接收缓冲区指针
extern u8 COMBUF[256];        // 接收缓冲区,最大256个字节
extern u8 ComNow;             // 5个COM共用公共接收缓冲区COMBUF,以此区分串口号
void US123ART45Init(u8 iCOM,u32 baudRate,u8 Tx8Rx4,u8 priPS,u8 Ds1908,u8 St0115,u8 y1n0CRC,u8 HFr1c2);
#endif
//-------------------------------------------- end of AHR_USART.H ------------------------------------

评分

参与人数 1 ST金币 +20 收起 理由
STMCU + 20

查看全部评分

收藏 评论3 发布时间:2018-12-3 11:19

举报

3个回答
aiherong 回答时间:2018-12-3 11:22:18



//===================== AiHeRong.H ========================== 2018-0712 ===============================
#include "stm32f10x.h"
#define SYSCLK 72
#define REALADDR(addrNum) *((volatile unsigned long *)(addrNum))
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr))
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) //bit-baud is CMSIS 功能 20180426

//凡艾和荣编写的工程均包含该文件,包括最典型的宏定义和最广泛的移植要点!  【目标】:所有移植全在此进行!!
#include "AHR_TouchFilm.h"
#include "AHR_SysTick.h"
#include "AHR_Lcdtft.h"
#include "AHR_24Cxx.h"
#include "AHR_usart.h"
#include "spi.h"
// 各模块的依存关系要说明,独立性依次为:->SysTick->LcdTFT,24Cxx->TouchFilm-> ....
#include  <stdio.h>
#include  <stdlib.h>
#include  <stdarg.h>
#include  <math.h>
#include  <cpu.h>
#include  <lib_def.h>
#include  <lib_ascii.h>
#include  <lib_math.h>
#include  <lib_mem.h>
#include  <lib_str.h>
#include  <bsp.h>
#include  <os.h>
int  SystemDeviceInit(void);  // 为uCOSiii的主函数规范而集中初始化设备 全成功才返回TRUE;  20180922
// 以下暂时保留:  2018-08-09
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C  
#define GPIOA_IDR_Addr    (GPIOA_BASE+ 8) //0x40010808
#define GPIOB_IDR_Addr    (GPIOB_BASE+ 8) //0x40010C08
#define GPIOC_IDR_Addr    (GPIOC_BASE+ 8) //0x40011008
#define GPIOD_IDR_Addr    (GPIOD_BASE+ 8) //0x40011408
#define GPIOE_IDR_Addr    (GPIOE_BASE+ 8) //0x40011808
#define GPIOF_IDR_Addr    (GPIOF_BASE+ 8) //0x40011A08
#define GPIOG_IDR_Addr    (GPIOG_BASE+ 8) //0x40011E08
//IO口操作,只对单一的IO口! //确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入
#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入
#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入
#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入
#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入
#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入
#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入
//------------------------------------------------------ end of AiHeRong.H ----------------------------
aiherong 回答时间:2019-1-9 19:59:41
以下是在main()显示接收缓冲区内容:
while (USART_GetITStatus(USART2,USART_IT_RXNE)==RESET) //在接收中断之外读全局数组COMBUF
            if((REALADDR(USART2_BASE)&0x20)==0) 或 if(USART_GetITStatus(USART2,USART_IT_RXNE)==RESET)
       for (i=iComBuf;i<N_BUF;i++) {
            LCD_ShowChar(i*8,60,(char)COMBUF[i],16,0);
       }
aiherong 回答时间:2019-4-26 07:56:03
由于时间局促去了解USART而写了上面帖子,其中存有缺陷: 没有注意到USART1挂APB2这一特殊性,从而波特率数组里对应的值都要减半!(其它串口不必改动)

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版