OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 2321|回复: 6

UCOSII下读取单总线温湿度传感器出错如何解决?

[复制链接]

18

主题

61

帖子

0

精华

初级会员

Rank: 2

积分
178
金钱
178
注册时间
2013-4-24
在线时间
6 小时
发表于 2016-11-4 16:22:38 | 显示全部楼层 |阅读模式
我用STM32读取AM2301温湿度传感器,裸机跑的时候读取正常的,但是运行UCOSII系统后,读取的数据是不对的,就是偶尔有几个数据位不对。类似DS18B20的单总线通信对时序要求很高,不知道是不是因为UCOS系统产生调度的原因。

我在读取温湿度前后加入了     OSSchedLock();    OSSchedUnlock();    也不能解决问题      


void AM2301_task(void *pdata)
{
                u8 i;
               
                while(1)
                {
                         OSSchedLock();
                        AM2301_READ();//读取温湿度数值         
                        OSSchedUnlock();//恢复调度                                                      
                        for(i=0;i<10;i++)
                        {
                                     delay_ms(1000);
                       }
                }                                                                        
}


void   AM2301_OUT(void)
{
                 GPIO_InitTypeDef  GPIO_InitStructure;
                 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);        
                 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;                                
                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                  //推挽输出
                 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;                 //IO口速度为2MHz
                 GPIO_Init(GPIOB, &GPIO_InitStructure);                                         //根据设定参数初始化
}

void   AM2301_IN(void)
{
                 GPIO_InitTypeDef  GPIO_InitStructure;
                 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);        
                 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;                                
                 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;                 
                 GPIO_Init(GPIOB, &GPIO_InitStructure);                                         //根据设定参数初始化
}


u8  AM2301_Start(void)
{
                u16 count=0;
                AM2301_OUT();  //设置端口输出
                AM2301_DATOUT = 0;
                delay_ms(2);   //持续最低1ms
                AM2301_IN();               
                delay_us(35);
        
                count = 0;
                while(AM2301_DATIN==0)
                {
                                 delay_us(1);
                                 if(count++>500)
                                 {
                                                 count = 0;
                                                 return 1; //失败
                                 }
                }
                count = 0;
                while(AM2301_DATIN==1)
                {
                                 delay_us(1);
                                 if(count++>500)
                                 {
                                                 count = 0;
                                                 return 1; //失败
                                 }
                }               
                return 0;//成功
}


u8  AM2301_ReadValue(void)
{
     u8 i;
           u16 count;
           u8 data_temp=0;
           for(i=0;i<8;i++)
           {
                              data_temp<<=1;
                                                count = 0;
                                                while(AM2301_DATIN==0)
                                                {
                                                                 delay_us(1);
                                                                 if(count++>500)
                                                                 {
                                                                                 count = 0;
                                                                                 return 0xff; //失败
                                                                 }
                                                }
                                       
                                                delay_us(35);
                                                if(AM2301_DATIN==1)
                                                {
                                                          data_temp|=1;
                                                }
                                                else
                                                {
                                                          data_temp|=0;
                                                }        
                                                count = 0;
                                                while(AM2301_DATIN==1)
                                                {
                                                                 delay_us(1);
                                                                 if(count++>500)
                                                                 {
                                                                                 count = 0;
                                                                                 return 0xff; //失败
                                                                 }
                                                }                                                
           }
     return data_temp;   
}



u8  Get_data(unsigned char *buf)
{
    u8 i,j;
          u8 databuf1[5];
          for(i=0;i<5;i++)
          {
        j = AM2301_ReadValue();
                          if(j==0xff)
                                         return 1;//失败
                                else
                                        databuf1= j;
          }
                j= databuf1[0]+databuf1[1]+databuf1[2]+databuf1[3];
                if(databuf1[4]==j)
                {
                           for(i=0;i<5;i++)
                               *(buf+i) = databuf1;
                //if( *(buf+4) == *(buf+0)+*(buf+1)+*(buf+2)+*(buf+3) )
        return 0;
                }
    else
        return 1;
}


u8 AM2301_READ(void)//读取温湿度数值
{
     u8 DHTData[5];
           u16 tempv;
                 if(AM2301_Start()==1)
                           return 1;

                 if(Get_data(DHTData)==1)
                 {
                                        return 1;
                 }
                 else
                 {
                            tempv =    (DHTData[2]<<8)+DHTData[3];
                            if( (tempv&0x8000)==0x8000 )//负数
                                        {
                                            Temp_value = -( (tempv&0x7fff)/10 + ((tempv&0x7fff)%10)*0.1);
                                        }
                                        else
                                        {
                                                  Temp_value =  tempv/10 + (tempv%10)*0.1;
                                        }
                            tempv =    (DHTData[0]<<8)+DHTData[1];
                                        Hum_value =  tempv/10 + (tempv%10)*0.1;
          return 0;  
                 }
}

//延时nus
//nus为要延时的us数.                                                                                       
void delay_us(u32 nus)
{               
        u32 ticks;
        u32 told,tnow,tcnt=0;
        u32 reload=SysTick->LOAD;        //LOAD的值                     
        ticks=nus*fac_us;                         //需要的节拍数                           
        tcnt=0;
        told=SysTick->VAL;                //刚进入时的计数器值
        while(1)
        {
                tnow=SysTick->VAL;        
                if(tnow!=told)
                {            
                        if(tnow<told)tcnt+=told-tnow;//这里注意一下SYSTICK是一个递减的计数器就可以了.
                        else tcnt+=reload-tnow+told;            
                        told=tnow;
                        if(tcnt>=ticks)break;//时间超过/等于要延迟的时间,则退出.
                }  
        };                                                                             
}
//延时nms
//nms:要延时的ms数
void delay_ms(u16 nms)
{        
        if(OSRunning==TRUE)//如果os已经在跑了            
        {                  
                if(nms>=fac_ms)//延时的时间大于ucos的最少时间周期
                {
                           OSTimeDly(nms/fac_ms);//ucos延时
                }
                nms%=fac_ms;                                //ucos已经无法提供这么小的延时了,采用普通方式延时   
        }
        delay_us((u32)(nms*1000));        //普通方式延时,此时ucos无法启动调度.
}

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

26

帖子

0

精华

初级会员

Rank: 2

积分
111
金钱
111
注册时间
2015-1-6
在线时间
16 小时
发表于 2016-11-5 18:24:54 | 显示全部楼层
在采集传感器的时候将中断关了试试
回复 支持 反对

使用道具 举报

3

主题

548

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1383
金钱
1383
注册时间
2015-2-3
在线时间
197 小时
发表于 2016-11-5 22:49:58 | 显示全部楼层
本帖最后由 yyx112358 于 2016-11-5 22:56 编辑

加入调度锁不行,同时是间隔性的错误,估计是被其它的中断打断了,楼主先看看可能是哪个中断(是不是周期性的?出错时有没有什么外设工作?),能找到就修改一下。不行的话就关中断看看。
回复 支持 反对

使用道具 举报

3

主题

548

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1383
金钱
1383
注册时间
2015-2-3
在线时间
197 小时
发表于 2016-11-5 23:08:22 | 显示全部楼层
[mw_shl_code=c,true]delay_us(35);
                                                if(AM2301_DATIN==1)
                                                {
                                                          data_temp|=1;
                                                }
                                                else
                                                {
                                                          data_temp|=0;
                                                }        [/mw_shl_code]
看了下代码,是靠延时一段时间之后读取,这种方法可靠性堪忧啊……
要可靠的话,提个建议:
1.用外部中断读取,中断函数里面用状态机。缺点是中断有点频繁,而且仍然有失败风险
2.有个未经验证的想法:设定一个定时器,再在内存建立一个时间表,用边沿触发DMA。DMA负责在来一个边沿的时候直接把定时器计数值传入内存,8次之后触发DMA中断然后对这一串时间进行解码就行。楼主如果这种方法成功了记得叫我哈
回复 支持 反对

使用道具 举报

7

主题

58

帖子

0

精华

初级会员

Rank: 2

积分
194
金钱
194
注册时间
2016-10-11
在线时间
43 小时
发表于 2016-11-5 23:19:20 | 显示全部楼层
兄弟,你的问题出现在有没有带操作性系统问题上,,那你想他们两个有啥本质区别,,就是发生了任务调度。。然而,,所有带延时的delay都会发生任务调度,,所以。。。你试试自己用for循环写延迟函数试试。。。我目前的项目,,内部结构的延时基本自己写的for循环,特别是芯片初始化这过程。。希望你按照我说的试试,,90%解决问题。。
回复 支持 反对

使用道具 举报

18

主题

61

帖子

0

精华

初级会员

Rank: 2

积分
178
金钱
178
注册时间
2013-4-24
在线时间
6 小时
 楼主| 发表于 2016-11-7 23:24:54 | 显示全部楼层
yyx112358 发表于 2016-11-5 23:08
[mw_shl_code=c,true]delay_us(35);
                                                if(AM2301_DATIN== ...

你这个做法貌似太繁琐了, 我靠延时有啥问题么?有啥致命的问题?
回复 支持 反对

使用道具 举报

18

主题

61

帖子

0

精华

初级会员

Rank: 2

积分
178
金钱
178
注册时间
2013-4-24
在线时间
6 小时
 楼主| 发表于 2016-11-7 23:25:24 | 显示全部楼层
dingyu000111 发表于 2016-11-5 23:19
兄弟,你的问题出现在有没有带操作性系统问题上,,那你想他们两个有啥本质区别,,就是发生了任务调度。。 ...

我屏蔽中断就可以了,看来不是发生调度,是中断的原因导致的
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-5-24 22:08

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表