红枫
红枫 - 认证专家
This guy hasn't written anything yet

注册于 1 year ago

回答
256
文章
4
关注者
30

wifi模块的耗电比较大,有时供电不足会有各种问题

uart+dma使用时uart的idle超时会导致分包,这是完全由硬件控制完成的,没办法避免。如果使用中断方式可通过自己设计驱动达到期望的功能。

串口引脚用的是哪些?打开方式是什么样的?你的提问给的信息太少了。

将shell线程的堆栈设大些,命令行的最大长度配置也改大些,默认是128

请检查硬件驱动加了没有,须先启动设备驱动注册设备到设备树,然后才能在应用中找到设备。

写入速度主要取决于三个方面,1.sdio速率,2.flash写入时间,3.mcu主频,可以从这三个方面尝试提升。

操作系统会在处理临界区数据时关中断,单纯依靠在中断处理中收发数据是不行的,我以前使用定时器的输入捕获和比较输出功能做过模拟串口,9600速率是没问题的,看看你的收发引脚在不在定时器通道上。

提供一段红外口通信的驱动代码,是通过定时器模拟串口功能实现的,很久以前的代码了,使用的还是以前的stm32标准库,不过原理相同的,希望对你有所帮助.

//--------------------------------------------------------------------
//文件名    :    IRComPort.c
//创建人    :    齐永忠
//创建日期:    2009.10.29
//--------------------------------------------------------------------
#include "IRComPort.h"
#include "Debug.h"
#include "QQueue.h"

//--------------------------------------------------------------------

#define IR_RX_PORT                    GPIOB
#define IR_TX_PORT                    GPIOB

#define IR_RX_PIN                    GPIO_Pin_1
#define IR_TX_PIN                    GPIO_Pin_0
#define IR_TX_NO                    0            //红发发送脚对应脚号

#define IR_RX_TIMER                TIM3//接收定时器定义
#define IR_TX_TIMER                TIM2//发送定时器定义
#define IR_PWM_TIMER                TIM3//PWM定时器定义

#define IR_RX_CHNNL                TIM_IT_CC4//中断源
#define IR_TX_CHNNL                TIM_IT_CC1//中断源
#define IR_PWM_CHNNL                TIM_IT_CC3//中断源

#define IR_RX_CAP_CHNNL            TIM_Channel_4//定时器信道,需与中断源一致
#define IR_PWM_CMD_CHNNL        TIM_Channel_3//定时器信道,需与中断源一致

#define IRCOM_RX_IRQCHANNEL            TIM3_IRQChannel//中断信道,需与定时器一致
#define IRCOM_TX_IRQCHANNEL        TIM2_IRQChannel//中断信道,需与定时器一致

#define TIMER_PRESCALER            6// 定时器预分频值

#define IRCOM_BYTE_TIMEOUT        20    //红外口字节超时时间Ticks

#define IRCOM_QUEUE_LEN            64//红外口队列长度

#define IRCOM_RX_QUEUE_PTR        ((PQQUEUE)IRComRxQueue)  //红外口队列指针
#define IRCOM_TX_QUEUE_PTR        ((PQQUEUE)IRComTxQueue)  //红外口队列指针

//--------------------------------------------------------------------

typedef struct{
    u16 BitTClkNum;
    u16 BaudRate;
    u8  DataBit;
    u8  Parity:2;
    u8  StopBit:2;
    u8  ParityErr:1;
    u8  TxParity:1;
    u8  RxComMode:1;
    u8  RXStep:4;
    u8  TXStep:4;
    u8  RXChar;
    u8  TXChar;
}IRCOMDATA;
//--------------------------------------------------------------------

const u8 BitMask[] = {1<<0,1<<1,1<<2,1<<3,1<<4,1<<5,1<<6,1<<7};

const GPIO_InitTypeDef      IRComRx         = {IR_RX_PIN, GPIO_Speed_2MHz, GPIO_Mode_IN_FLOATING};//接收脚输入浮空
const GPIO_InitTypeDef    IRComTx        = {IR_TX_PIN, GPIO_Speed_2MHz, GPIO_Mode_IN_FLOATING};//发送脚复用功能开漏输出

const NVIC_InitTypeDef    IRComRx_NVIC_InitStruct={IRCOM_RX_IRQCHANNEL, 0, 2, ENABLE};
const NVIC_InitTypeDef    IRComTx_NVIC_InitStruct={IRCOM_TX_IRQCHANNEL, 0, 2, ENABLE};

const TIM_TimeBaseInitTypeDef IRTimerBaseCfg = {TIMER_PRESCALER-1, TIM_CounterMode_Up, 0xffff, TIM_CKD_DIV1, 0};

const TIM_ICInitTypeDef IRRxICCfg = {IR_RX_CAP_CHNNL, TIM_ICPolarity_Falling, TIM_ICSelection_DirectTI, TIM_ICPSC_DIV1, 0};
const TIM_OCInitTypeDef IRTROCCfg = {TIM_OCMode_Timing, TIM_OutputState_Disable, 0, 0, 0, 0, 0, 0};
const TIM_OCInitTypeDef IRTxPWMCfg= {TIM_OCMode_PWM1, TIM_OutputState_Enable, 0, 0, 0, 0, 0, 0};

//--------------------------------------------------------------------

static IRCOMDATA IRComData;

static u8 IRComRxQueue[sizeof(QQUEUE)+IRCOM_QUEUE_LEN];//接收队列数据定义
static u8 IRComTxQueue[sizeof(QQUEUE)+IRCOM_QUEUE_LEN];//发送队列数据定义
//--------------------------------------------------------------------
static void SetPWMOutput(bool IsEnabled)
{
    register u32 Cr;

#if IR_TX_NO <= 7
    Cr = IR_TX_PORT->CRL;
#else
    Cr = IR_TX_PORT->CRH;
#endif

    Cr &= ~(0x0000000F<<((IR_TX_NO%8)<<2));
    if(IsEnabled)
        Cr |= (0x0000000E<<((IR_TX_NO%8)<<2));
    else
        Cr |= (0x00000004<<((IR_TX_NO%8)<<2));

#if IR_TX_NO <= 7
    IR_TX_PORT->CRL = Cr;
#else
    IR_TX_PORT->CRH = Cr;
#endif
}
//--------------------------------------------------------------------
static void TIM_OCxInit(TIM_TypeDef * TIMx, u16 TIM_Channel, TIM_OCInitTypeDef * TIM_OCInitStruct)
{
    switch(TIM_Channel)
    {
        case TIM_IT_CC1:
            TIM_OC1Init(TIMx, TIM_OCInitStruct);
            break;
        case TIM_IT_CC2:
            TIM_OC2Init(TIMx, TIM_OCInitStruct);
            break;
        case TIM_IT_CC3:
            TIM_OC3Init(TIMx, TIM_OCInitStruct);
            break;
        case TIM_IT_CC4:
            TIM_OC4Init(TIMx, TIM_OCInitStruct);
            break;
    }
}
//--------------------------------------------------------------------
static void TIM_SetCompare(TIM_TypeDef * TIMx, u16 TIM_Channel, u16 Compare)
{
    switch(TIM_Channel)
    {
        case TIM_IT_CC1:
            TIM_SetCompare1(TIMx, Compare);
            break;
        case TIM_IT_CC2:
            TIM_SetCompare2(TIMx, Compare);
            break;
        case TIM_IT_CC3:
            TIM_SetCompare3(TIMx, Compare);
            break;
        case TIM_IT_CC4:
            TIM_SetCompare4(TIMx, Compare);
            break;
    }
}
//--------------------------------------------------------------------
static u16 TIM_GetCapture(TIM_TypeDef * TIMx, u16 TIM_Channel)
{
    switch(TIM_Channel)
    {
        case TIM_IT_CC1:
            return(TIM_GetCapture1(TIMx));
        case TIM_IT_CC2:
            return(TIM_GetCapture2(TIMx));
        case TIM_IT_CC3:
            return(TIM_GetCapture3(TIMx));
        case TIM_IT_CC4:
            return(TIM_GetCapture4(TIMx));
    }
    return(0);
}
//--------------------------------------------------------------------
static bool CalParity(u8 ch)//奇数个1返回true
{
    ch^=(ch>>4);
    ch^=(ch>>2);
    ch^=(ch>>1);
    ch&=0x01;
    return((bool)(ch!=0));
}
//--------------------------------------------------------------------
static void IRComPortSetRxModeCap(void)//设置为接收捕获模式
{
    TIM_ITConfig(IR_TX_TIMER,IR_TX_CHNNL,DISABLE);//禁止发送比较中断
    TIM_Cmd(IR_TX_TIMER, DISABLE);//禁止发送定时器
    TIM_Cmd(IR_PWM_TIMER, DISABLE);//禁能PWM定时器

    IRComData.RxComMode = 0;
    TIM_ICInit(IR_RX_TIMER, (TIM_ICInitTypeDef *)&IRRxICCfg);//配置接收输入为下降沿捕获模式
    TIM_SetAutoreload(IR_RX_TIMER, 0xffff);//设置自动重装寄存器
    TIM_ClearITPendingBit(IR_RX_TIMER, IR_RX_CHNNL);//清中断标志
    TIM_ITConfig(IR_RX_TIMER,IR_RX_CHNNL,ENABLE);//使能接收捕获中断
    TIM_Cmd(IR_RX_TIMER, ENABLE);//使能接收定时器
}
//--------------------------------------------------------------------
static void IRComPortRxCapToComp(void)//由捕获模式转换到比较模式
{
    static u16 CapVol;
    IRComData.RxComMode = 1;
    CapVol = TIM_GetCapture(IR_RX_TIMER, IR_RX_CHNNL)+IRComData.BitTClkNum/2;
    TIM_OCxInit(IR_RX_TIMER, IR_RX_CHNNL, (TIM_OCInitTypeDef *)&IRTROCCfg);//配置接收比较模式
    TIM_SetCompare(IR_RX_TIMER, IR_RX_CHNNL, CapVol);//设置比较值
    TIM_ClearITPendingBit(IR_RX_TIMER, IR_RX_CHNNL);//清中断标志
}
//--------------------------------------------------------------------
static void IRComPortRxCompToCap(void)//由接收比较转换到接收捕获模式
{
    IRComData.RxComMode = 0;
    TIM_ICInit(IR_RX_TIMER, (TIM_ICInitTypeDef *)&IRRxICCfg);//配置接收输入为下降沿捕获模式
    TIM_ClearITPendingBit(IR_RX_TIMER, IR_RX_CHNNL);//清中断标志
}
//--------------------------------------------------------------------
static void IRComPortStartupSend(void)//红外口启动发送
{
    RCC_ClocksTypeDef RCC_Clocks;
    u32 TIM_Clocks;

    RCC_GetClocksFreq(&RCC_Clocks);//取时钟频率
    if(RCC_Clocks.HCLK_Frequency == RCC_Clocks.PCLK1_Frequency)
        TIM_Clocks = RCC_Clocks.PCLK1_Frequency;
    else
        TIM_Clocks = RCC_Clocks.PCLK1_Frequency * 2;

    TIM_ITConfig(IR_RX_TIMER,IR_RX_CHNNL,DISABLE);//禁止接收捕获中断
    TIM_Cmd(IR_PWM_TIMER, DISABLE);//禁能PWM定时器
    TIM_OCxInit(IR_PWM_TIMER, IR_PWM_CHNNL, (TIM_OCInitTypeDef *)&IRTxPWMCfg);//配置PWM 定时器为PWM 模式
    TIM_SetAutoreload(IR_PWM_TIMER, TIM_Clocks/38000/TIMER_PRESCALER);//设置自动重装寄存器,周期值
    TIM_SetCompare(IR_PWM_TIMER, IR_PWM_CHNNL, TIM_Clocks/38000/TIMER_PRESCALER/2);//占空比50%
    TIM_SetCounter(IR_PWM_TIMER, 0);//设置计数器值
    TIM_Cmd(IR_PWM_TIMER, ENABLE);//使能PWM定时器
    
    IRComData.TXStep = 0;
    TIM_OCxInit(IR_TX_TIMER, IR_TX_CHNNL, (TIM_OCInitTypeDef *)&IRTROCCfg);//配置发送定时器为输出比较模式
    TIM_SetCompare(IR_TX_TIMER, IR_TX_CHNNL, TIM_GetCounter(IR_TX_TIMER)+IRComData.BitTClkNum);//设置发送比较值
    TIM_ClearITPendingBit(IR_TX_TIMER, IR_TX_CHNNL);//清中断标志
    TIM_ITConfig(IR_TX_TIMER,IR_TX_CHNNL,ENABLE);//使能发送比较中断
    TIM_Cmd(IR_TX_TIMER, ENABLE);//使能发送定时器
    
}
//--------------------------------------------------------------------
void IRComPortInit(u32 Baudrate, VERIFYBIT Verifybit, STOPBIT Stopbit)
{
    RCC_ClocksTypeDef RCC_Clocks;
    u32 TIM_Clocks;

    RCC_GetClocksFreq(&RCC_Clocks);//取时钟频率
    if(RCC_Clocks.HCLK_Frequency == RCC_Clocks.PCLK1_Frequency)
        TIM_Clocks = RCC_Clocks.PCLK1_Frequency;
    else
        TIM_Clocks = RCC_Clocks.PCLK1_Frequency * 2;

    IRComData.BaudRate = Baudrate;
    IRComData.DataBit = 8;
    IRComData.Parity = Verifybit;
    IRComData.StopBit = Stopbit;
    IRComData.ParityErr = 0;
    IRComData.RXStep = 0;
    IRComData.TXStep = 0;
    IRComData.BitTClkNum = TIM_Clocks/TIMER_PRESCALER/IRComData.BaudRate;

    QQInit(IRCOM_RX_QUEUE_PTR,sizeof(IRComRxQueue));//接收队列初 始化
    QQInit(IRCOM_TX_QUEUE_PTR,sizeof(IRComTxQueue));//发送队列初 始化
    
    //IO口配置
    GPIO_Init(IR_RX_PORT, (GPIO_InitTypeDef *)&IRComRx);
    GPIO_Init(IR_TX_PORT, (GPIO_InitTypeDef *)&IRComTx);

    NVIC_Init((NVIC_InitTypeDef *)&IRComRx_NVIC_InitStruct);//中断向量配置
    NVIC_Init((NVIC_InitTypeDef *)&IRComTx_NVIC_InitStruct);//中断向量配置
    
    TIM_InternalClockConfig(IR_TX_TIMER);//设置使用内部时钟
    TIM_InternalClockConfig(IR_PWM_TIMER);//设置使用内部时钟

    TIM_TimeBaseInit(IR_TX_TIMER, (TIM_TimeBaseInitTypeDef *)&IRTimerBaseCfg );
    TIM_TimeBaseInit(IR_PWM_TIMER, (TIM_TimeBaseInitTypeDef *)&IRTimerBaseCfg );
    
     IRComPortSetRxModeCap();//设置为接收捕获模式
}
//--------------------------------------------------------------------
u32 IRComPortRead(u8 *pBuf, u32 MaxLen, u32 Timeout)
{
    register u32 i;
    register u32 Time;
    register bool Ack;

    ASSERT(pBuf != NULL);

    if(MaxLen == 0)
        return(0);

    Ack = false;
    i=0;
    Time = OSTimeGet();
    while(i < MaxLen)
    {
        u8 c;
        if(QQGetChar(IRCOM_RX_QUEUE_PTR,&c))//队列不空,取到数据
        {
            Ack = true;
            *(pBuf+i) = c;
            i++;
            Time = OSTimeGet();
        }
        else//队列空,未取到数
        {
            if(Ack)
            {
                if(OSTimeGet() - Time > IRCOM_BYTE_TIMEOUT)
                    break;
            }
            else
            {
                if((Timeout > 0)&&(OSTimeGet() - Time > Timeout))
                    break;
            }
            OSTimeDly(1);
        }
    }
    return(i);
}
//--------------------------------------------------------------------
u32 IRComPortWrite(u8 *pBuf, u32 Len, u32 Timeout)
{
    register u32 i;
    register u32 Time;
    register bool SendStart;

    ASSERT(pBuf != NULL);

    if(Len == 0)
        return(0);

    i = 0;
    SendStart = false;
    Time = OSTimeGet();
    
    while(i<Len)
    {    
        if(QQSetChar(IRCOM_TX_QUEUE_PTR, *(pBuf+i)))//队列不满,放数据成功
        {
            i++;
        }
        else
        {
            if(!SendStart)//如果未启动发送
            {
                SendStart=true;
                IRComPortStartupSend();//启动发送
            }
            if((Timeout>0)&&((OSTimeGet()-Time)>Timeout))
                break;
            OSTimeDly(1);
        }
    }
    if(!SendStart)//如果未启动发送
    {
        SendStart=true;
        IRComPortStartupSend();//启动发送
    }
    while(!QQChkEmpty(IRCOM_TX_QUEUE_PTR))//等待发送队列空
    {
        if((Timeout>0)&&((OSTimeGet()-Time)>Timeout))
            break;
        OSTimeDly(1);
    }
    OSTimeDly(1);//等待最后一字节发完
     
    return(i);
}

//--------------------------------------------------------------------
void IRComPortRxIntDeal(void)//接收捕获比较中断处理
{
    if (TIM_GetITStatus(IR_RX_TIMER, IR_RX_CHNNL) != RESET)//有捕获或比较 中断
    {
        TIM_ClearITPendingBit(IR_RX_TIMER, IR_RX_CHNNL);//清中断标志
        if(IRComData.RxComMode == 0)//捕获模式
        {
            IRComPortRxCapToComp();//由捕获模式转换到比较模式
            IRComData.RXStep = 0;
        }
        else//比较模式
        {
            u8 Status = GPIO_ReadInputDataBit(IR_RX_PORT, IR_RX_PIN);
            if(IRComData.RXStep == 0)//开始位处理
            {
                if(Status != RESET)//是高电平,开始位错误
                {
                    IRComPortSetRxModeCap();//设置到捕获模式
                }
                else//是低电平,开始位正确
                {
                    TIM_SetCompare(IR_RX_TIMER, IR_RX_CHNNL, TIM_GetCapture(IR_RX_TIMER, IR_RX_CHNNL)+IRComData.BitTClkNum);//设置比较值
                    IRComData.RXStep++;
                    IRComData.RXChar = 0;
                }
            }
            else if(IRComData.RXStep <= IRComData.DataBit)//数据位处理
            {
                TIM_SetCompare(IR_RX_TIMER, IR_RX_CHNNL, TIM_GetCapture(IR_RX_TIMER, IR_RX_CHNNL)+IRComData.BitTClkNum);//设置比较值
                if(Status != RESET)
                    IRComData.RXChar |= *(BitMask+IRComData.RXStep-1);
                IRComData.RXStep++;
            }
            else if(IRComData.RXStep == IRComData.DataBit+1)//校验或停止位处理
            {
                QQSetChar(IRCOM_RX_QUEUE_PTR, IRComData.RXChar);//放接收数据入接收队列
                if(IRComData.Parity != VB_NONE)//有校验位
                {
                    bool Parity = CalParity(IRComData.RXChar);//奇数个1返回true
                    if(IRComData.Parity == VB_ODD)
                    {
                        if(Parity == Status)//奇校验错误
                            IRComData.ParityErr = 1;
                        else
                            IRComData.ParityErr = 0;                            
                    }
                    else
                    {
                        if(Parity == Status)
                            IRComData.ParityErr = 0;
                        else
                            IRComData.ParityErr = 1;
                    }
                }
                IRComPortRxCompToCap();//由接收比较转换到接收捕获模式
            }
        }
    }
}
//--------------------------------------------------------------------
void IRComPortTxIntDeal(void)
{
    TIM_ClearITPendingBit(IR_TX_TIMER, IR_TX_CHNNL);//清中断标志
    if(IRComData.TXStep == 0)
    {
        if(QQGetChar(IRCOM_TX_QUEUE_PTR, &(IRComData.TXChar)))//如果队列不空,取数据成功
        {
            TIM_SetCompare(IR_TX_TIMER, IR_TX_CHNNL, TIM_GetCapture(IR_TX_TIMER, IR_TX_CHNNL)+IRComData.BitTClkNum);//设置发送比较值
            SetPWMOutput(true);//使能PWM 输出
            IRComData.TXStep++;
        }
        else//队列空,数据发送结束
        {
            IRComPortSetRxModeCap();//设置到接收捕获模式
        }
    }
    else if(IRComData.TXStep <= IRComData.DataBit)//处理数据位
    {
        TIM_SetCompare(IR_TX_TIMER, IR_TX_CHNNL, TIM_GetCapture(IR_TX_TIMER, IR_TX_CHNNL)+IRComData.BitTClkNum);//设置发送比较值
        if((IRComData.TXChar & (*(BitMask + IRComData.TXStep -1))) == RESET)
            SetPWMOutput(true);//使能PWM 输出
        else
            SetPWMOutput(false);//禁能PWM 输出
        IRComData.TXStep++;
    }
    else if(IRComData.TXStep == IRComData.DataBit+1)//处理数据位后一位
    {
        if(IRComData.Parity == VB_NONE)//无校验位,则发送停止位
        {
            TIM_SetCompare(IR_TX_TIMER, IR_TX_CHNNL, TIM_GetCapture(IR_TX_TIMER, IR_TX_CHNNL)+IRComData.BitTClkNum/2*(IRComData.StopBit+1));//设置发送比较值
            SetPWMOutput(false);//禁能PWM 输出
            IRComData.TXStep = 0;
        }
        else
        {
            bool Parity;
            TIM_SetCompare(IR_TX_TIMER, IR_TX_CHNNL, TIM_GetCapture(IR_TX_TIMER, IR_TX_CHNNL)+IRComData.BitTClkNum);//设置发送比较值
            Parity = CalParity(IRComData.TXChar);//奇数个1返回true
            if(IRComData.Parity == VB_ODD)//奇校验
            {
                if(Parity)//是奇数个1
                    SetPWMOutput(true);//使能PWM 输出
                else
                    SetPWMOutput(false);//禁能PWM 输出         
            }
            else if(IRComData.Parity == VB_EVEN)
            {
                if(Parity)//是奇数个1
                    SetPWMOutput(false);//禁能PWM 输出
                else
                    SetPWMOutput(true);//使能PWM 输出             
            }
            IRComData.TXStep++;
        }
    }
    else if(IRComData.TXStep == IRComData.DataBit + 2)//处理停止位
    {
        TIM_SetCompare(IR_TX_TIMER, IR_TX_CHNNL, TIM_GetCapture(IR_TX_TIMER, IR_TX_CHNNL)+IRComData.BitTClkNum/2*(IRComData.StopBit+1));//设置发送比较值
        SetPWMOutput(false);//禁能PWM 输出
        IRComData.TXStep = 0;
    }
}
//--------------------------------------------------------------------
#ifdef DEBUG
#include "Com1Port.h"
void IRComPortTest(void)
{
    Com1PortInit(1200, VB_EVEN, SB_1);
    IRComPortInit(1200, VB_EVEN, SB_1);
    while(1)
    {
        u8 Buf[128];
        u32 Len;
        Len = Com1PortRead(Buf, sizeof(Buf), OS_TICKS_PER_SEC/2);
            if(Len > 0)
            {
            IRComPortWrite(Buf,Len,OS_TICKS_PER_SEC*2);
                   Len = IRComPortRead(Buf,sizeof(Buf),OS_TICKS_PER_SEC*2);
            if(Len > 0)
                Com1PortWrite(Buf, Len, OS_TICKS_PER_SEC*2);
        }
    }
}
#endif
//--------------------------------------------------------------------

pos参数不被使用,传入参数值是多少都可以,使用-1是为了明确表示这是个无效参数,方便代码的阅读理解

使用ops占用ram更少,健壮性更好。

回到
顶部

发布
问题

投诉
建议