搜索
bottom↓
回复: 2

串口中断接收数据滤波问题

[复制链接]

出0入0汤圆

发表于 2012-10-10 22:38:03 | 显示全部楼层 |阅读模式
本帖最后由 fzxuecumt 于 2012-10-11 07:21 编辑

一个水罐自动上水的程序,基本流程是:串口0接收ZIGBEE的液位数据信号,然后根据液位信号控制现场电机的启停。TIME1检测串口数据的中断检测功能,当10S时间内没有数据接收就认为通信中断,此时就停泵。
但是现在的问题是现场来的数据波动太大,控制不是很精准。我想增加软件滤波功能,但是写的程序都无法执行,麻烦高手指点一下。


#include <avr/io.h>

#include <avr/interrupt.h>

#include <avr/pgmspace.h>

#include <util/delay.h>


#define Set_Bit(val, bitn)     (val |=(1<<(bitn)))

#define Clr_Bit(val, bitn)     (val&=~(1<<(bitn)))

#define Get_Bit(val, bitn)     (val &(1<<(bitn))

#define combit(x,y) (x^=(1<<y))               /*位取反*/

unsigned char LED_SEG[]  = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
unsigned char LED_BIT[]  = {0b11101111,0b11011111,0b10111111,0b01111111};
unsigned int  LED_Data[] = {0,0,0,0};
unsigned int  ret;
unsigned int Level;
volatile unsigned char startflag = 0,countnew = 0,countold = 0,count = 0,datacount = 0;
unsigned int Leveldata[10]= {},AveLevel = 0,SumLevel = 0,currentdata,olddata;


typedef unsigned char uchar;
typedef unsigned int  uint;
typedef unsigned long ulong;



#define fosc        (16000000UL)                        //系统时钟

#define SCH_MAX_TASKS        2        // 调度器支持的任务个数,用户在调用调度器的时候必须设置

#define TXB8         0
#define RXB8        1
#define UPE         2
#define OVR         3
#define FE          4
#define UDRE        5
#define RXC         7

#define FRAMING_ERROR       (1<<FE)
#define PARITY_ERROR        (1<<UPE)
#define DATA_OVERRUN        (1<<OVR)
#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE         (1<<RXC)



// 定义调度器数据结构,每一个任务消耗 4 bytes RAM
typedef struct
{
         //定义函数类型指针,const关键字意思是这是一个指向flash的指针
         const void (*pTask)(void);
         uchar Delay;                // 任务第一次被执行前的延迟时间,如果为0则立即执行
         uchar Period;               // 任务的执行间隔时间,如果为0,则只执行一次
         uchar RunMe;                // 任务执行标志位:1 等待执行,0 不需要执行
} sTask;                            // sTask是结构体变量

uchar Comm0Temp[50];

//static uchar *pUsartRece1 = Comm1Temp,*pUsartRece0 = Comm0Temp;
static uchar *pUsartRece0 = Comm0Temp;
uchar Rcounter0,Rcounter1;

volatile uchar usart0_recv_flag=0;                //usart0接收到字符串标志
volatile uchar usart1_recv_flag=0;                //usart1接收到字符串标志

volatile uchar SameFrameFlag0 = 3;                //不等于0为同一帧,否则为下一帧
volatile uchar SameFrameFlag1 = 3;

sTask SCH_tasks_G[SCH_MAX_TASKS];                 //任务调度器数组

void Usart0CommandDeal(void);
void PumbCommandDeal(void);

//定时器0初始化
void SCH_Init_T0(void)
{
         TCNT0=0;
         TCCR0 = ((1<<WGM01)|(7<<CS00));          // 1024分频
         OCR0=130;                                                            // 108:10ms,130:12ms,162:15ms t(ms)=10*OCR0/108
         TIMSK |= (1<<OCIE0);                      // Interrupt Timer 0 enabled
}

//定时器1初始化
void SCH_Init_T1(void)
{
        TCCR1A = 0x00;       
        TCCR1B = 0x0d;        //1024分频
        TCCR1C = 0X00;       
        TIMSK |= 0x10;        //定时器1输出匹配A比较中断使能
        //OCR1A = 62500;        //定时时间1S,(1024*OCR1A)/16MHZ =time
        OCR1A = 15625;        //定时时间1S,(1024*OCR1A)/16MHZ =time
                                        //OCR1A = (time*16MHZ)/1024
       
}

//增加任务
uchar SCH_Add_Task( const void (*pFunction)(void), uchar DELAY, uchar PERIOD)
{
         uchar Index = 0;
         while ((SCH_tasks_G[Index].pTask != 0) && (Index < SCH_MAX_TASKS))// Have we reached the end of the list?        
        {
                 Index++;
         }
        if (Index == SCH_MAX_TASKS)// Task list is full
         {
                 return SCH_MAX_TASKS;
         }
         SCH_tasks_G[Index].pTask  = pFunction;        // If we're here, there is a space in the task array
         SCH_tasks_G[Index].Delay  = DELAY;
         SCH_tasks_G[Index].Period = PERIOD;
         SCH_tasks_G[Index].RunMe  = 0;
         return Index; // return position of task (to allow later deletion)
}


//TIME0中断服务程序
SIGNAL(TIMER0_COMP_vect)//(SIG_OVERFLOW0)
{
         uchar Index;
         for ( Index = 0;  Index < SCH_MAX_TASKS;  Index++ )
         {
                 if (SCH_tasks_G[Index].Delay == 0)
                 {
                         //给可以被调度的任务设置标志位
                         //说明:任务运行标志位不具有存储功能,也就是说,如果在规定的
                         //      间隔内没有被运行,则机会丧失
                         SCH_tasks_G[Index].RunMe = 1;  // Inc. the 'Run Me' flag
                         SCH_tasks_G[Index].Delay = SCH_tasks_G[Index].Period;//将任务需要的延时装入
                 }
                 else
                 {
                         SCH_tasks_G[Index].Delay --;//延时-1
                 }
         }
}

//TIME1中断服务程序
SIGNAL(SIG_OUTPUT_COMPARE1A)
{

                combit(PORTD,0);        //1S指示灯翻转一次
                //Leveldata[count] = (Comm0Temp[16] - 48)*1000 + ((Comm0Temp[17] - 48))*100 + ((Comm0Temp[19] - 48))*10 + ((Comm0Temp[20] - 48));
                count++;               
                if(count == 10)                //10S一个检测周期
                {
                       
                        count = 0;
                       
                        if(countnew == countold)
                        {
                                startflag = 0;                        //电机停止标志位
                               
                        }
                        else
                        {
                                startflag = 1;                        //电机启动志位
                                countold = countnew;
                        }
                }
       
}

//串口0初始化
void usart0_init( uint baud )
{
         uint UBRR;
         PORTE|=0x03;
         DDRE|=0x03;
         UBRR=(fosc/16/baud)-1;
         /* 设置波特率*/
         UBRR0H = (UBRR>>8);
         UBRR0L = UBRR;

        UCSR0B = (1<<RXCIE0)|(1<<TXCIE0)|(1<<RXEN0)|(1<<TXEN0);        /* 接收器与发送器使能*/
         
        UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);        /* 设置帧格式: 8 个数据位, 1 个停止位 */
}

// 定义 USART0 接收变量**********************************************
#define RX_BUFFER_SIZE0 50

uchar rx_buffer0[RX_BUFFER_SIZE0];        //接收缓存

// USART0 写、读指示及缓存中数据的字节数
volatile uchar rx_wr_index0=0;
volatile uchar rx_rd_index0=0;
volatile uchar rx_counter0=0;

// USART0 接收中断*****************************************************
SIGNAL(SIG_UART0_RECV)
{
         uchar Temp;
         usart0_recv_flag=1;
         SameFrameFlag0=3;
                 combit(PORTD,5);         //数据接收指示灯
                 countnew++;                //接收数据累加,通信检测
                 datacount++;                //数字滤波使用
                 //判断有无错误,(FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN)=0X1C
         if((UCSR0A&(FRAMING_ERROR|PARITY_ERROR|DATA_OVERRUN))==0)
         {
                 rx_buffer0[rx_wr_index0]=UDR0;                //接收数据至缓存区
                 if(++rx_wr_index0==RX_BUFFER_SIZE0)
                         rx_wr_index0=0;                        //缓存区满后写指示指向缓存区头
                 
                if(++rx_counter0==RX_BUFFER_SIZE0)                        //缓存区数据满后
                         rx_counter0=0;                                //清零字节记数值
         }
         else
                 Temp=UDR0;
}

// USART0 将缓存区数据读出到数组
uchar usart0_getstring(uchar *pGet)
{
         uchar n=0;
         while(rx_counter0)
         {
                 *pGet++=rx_buffer0[rx_rd_index0];
                 if(++rx_rd_index0==RX_BUFFER_SIZE0)
                         rx_rd_index0=0;                        //缓存数据读完后读指示指向缓存区头
                 asm volatile("cli");
                 --rx_counter0;
                 asm volatile("sei");
                 n++;
         }
         return n;
}

#define TX_BUFFER_SIZE0 50

uchar tx_buffer0[TX_BUFFER_SIZE0];                        //发送缓存

// USART0 发送读写指示及缓存区字节数
volatile uchar tx_wr_index0=0;
volatile uchar tx_rd_index0=0;
volatile uchar tx_counter0=0;

// USART0 发送***************************************************************
SIGNAL(SIG_UART0_TRANS)                                        // USART0 发送中断
{
         if(tx_counter0)
         {
                 tx_counter0-=1;                                //发送字节数减一
                 UDR0=tx_buffer0[tx_rd_index0];                        //缓存区数据载入发送寄存器
                 if((++tx_rd_index0)==TX_BUFFER_SIZE0)
                         tx_rd_index0=0;                                //如果数据发送完读指示指向缓存区头
         }
}

// USART0 将数据写入发送缓存区
void usart0_putchar(uchar c)
{
         while(tx_counter0>=TX_BUFFER_SIZE0);                //等待发送缓存中数据发送
         asm volatile("cli");                                //关全局中断
         
        //如果缓存区有数据或正在发送数据
         if(tx_counter0||((UCSR0A&DATA_REGISTER_EMPTY)==0))
         {
                 tx_buffer0[tx_wr_index0]=c;                //数据写入缓存区
                 if((++tx_wr_index0)==TX_BUFFER_SIZE0)tx_wr_index0=0;
                 tx_counter0+=1;
         }
         else
        {
                 UDR0=c;
         }
         asm volatile("sei");
         asm volatile("nop");
}

// USART0 发送ram中的字符串
void usart0_putramstring(uchar *str,uchar n)
{
         while(n--)
         {
                 usart0_putchar( *str++ );
         }
}

// USART0 发送flash中的字符串
void usart0_putflashstring(char *str)
{
         uchar temp=pgm_read_byte(str);
         while(temp!='\0')
         {
                 usart0_putchar( temp );
                 temp=pgm_read_byte(++str);
         }
}

// USART0 发送n字符
void Usart0PutNChar(uchar *str,uchar n)
{
         uchar i;
         for(i=0;i<n;i++)
         {
                 usart0_putchar( *str++ );
         }
}
  

//LED初始化
void Led_Init(void)
{
   DDRA=0xFF;   //数据端口
   PORTA=0xFF;
   DDRB=0x0F;   //数据端口
   PORTB=0xFF;
   DDRE=0xF0;   //控制端
   PORTE=0xF0;
   DDRD = 0XFF;
   PORTD = 0XFF;          

}

void sys_init(void)
{
         usart0_init(9600);
                 Led_Init();
         asm("sei");
         usart0_putflashstring(PSTR("SYSTEM Init,please wait!"));
         usart0_putchar( '\r' );
         usart0_putchar( '\n' );
         SCH_Add_Task((void*)Usart0CommandDeal, 1, 2);
         SCH_Add_Task((void*)PumbCommandDeal, 0, 2);
         SCH_Init_T0();
                 SCH_Init_T1();
}

void Usart0CommandDeal(void)
{
         
                 //static uchar *pUsartRece0 = Comm0Temp;
         //uchar Rcounter0;
                 
         if(SameFrameFlag0)
                 SameFrameFlag0--;
         if(usart0_recv_flag)        //接收数据,是同一帧的数据合并
         {
                 usart0_recv_flag = 0;
                 Rcounter0 = usart0_getstring(pUsartRece0);
                 if(SameFrameFlag0)
                 {
                         pUsartRece0 += Rcounter0;
                         if(pUsartRece0 - Comm0Temp > 100)
                         {
                                 Usart0PutNChar(Comm0Temp,pUsartRece0 - Comm0Temp);
                                 pUsartRece0 = Comm0Temp;
                         }
                 }
                                // currentdata = (Comm0Temp[16] - 48 )*1000 +(Comm0Temp[17] - 48)*100 + (Comm0Temp[19] - 48)*10 + (Comm0Temp[20] -48);
                               
         }
                 
         if(SameFrameFlag0 == 0)        //一帧接收完,处理数据
         {
                 SameFrameFlag0 = 3;
                 Rcounter0 = pUsartRece0 - Comm0Temp;
                 pUsartRece0 = Comm0Temp;
                 Usart0PutNChar(Comm0Temp,Rcounter0);       
                                 currentdata = (Comm0Temp[16] - 48 )*1000 +(Comm0Temp[17] - 48)*100 + (Comm0Temp[19] - 48)*10 + (Comm0Temp[20] -48);//获取液位数据
                                 Leveldata[datacount] = currentdata;
                                  if( datacount == 10)
                                  {
                                        datacount = 0;
                                        for ( unsigned char i = 0;i < 10;i++)
                                        {
                                                SumLevel + =  Leveldata;
                                                       
                                        }
                                        AveLevel = SumLevel/10;///数据处理部分,但是数据始终不对,放在中断里也不行
                 }                 
               
}

void PumbCommandDeal(void)
{
               

                LED_Data[0] =currentdata/1000;
                LED_Data[1] =(currentdata%1000)/100;
                LED_Data[2] =(currentdata%100)/10;
                LED_Data[3] =currentdata%10;        
                       
                for(uchar i = 0;i < 4;)
        {
            PORTA =LED_SEG[LED_Data]; //数码管显示数据
            PORTE =LED_BIT;                           //数码管显示允许
            _delay_ms(5);
            i++;
        }                 
                       
                Level = currentdata;
                       
                if(startflag == 1)                                        //控制电机启停
                {
                       
                        if(Level < 1550)       
                        {       
                                Clr_Bit(PORTD,7);                        //启动电机指示灯
                                Clr_Bit(PORTB,0);                        //启动电机                               
                        }
                       
                        if(Level > 1820)               
                        {
                                Set_Bit(PORTD,7);                        //停止电机指示灯
                                Set_Bit(PORTB,0);                        //停止电机                               
                        }                       
                       
                }
                else
                {
                        Set_Bit(PORTD,7);                                //停止电机指示灯
                        Set_Bit(PORTB,0);                                //停止电机
                }               
       
}

int main(void)
{
        uchar Index;
         
        sys_init();
         
        while(1)
         {
                 // 调度器调度任务
                 for (Index = 0; Index < SCH_MAX_TASKS; Index++)
                 {
                         if (SCH_tasks_G[Index].RunMe)
                        {
                                 (*SCH_tasks_G[Index].pTask)();              // 运行任务
                                 SCH_tasks_G[Index].RunMe = 0;                // 清除任务标志位
                        }
                 }
                                 
         }
}

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2012-10-10 22:54:05 | 显示全部楼层
本帖最后由 Mr_Mo 于 2012-10-10 22:55 编辑

/*        LZ试试下面这段        */




if(SameFrameFlag0 == 0)        //一帧接收完,处理数据
{
    SameFrameFlag0 = 3;
    Rcounter0 = pUsartRece0 - Comm0Temp;
    pUsartRece0 = Comm0Temp;
    Usart0PutNChar(Comm0Temp,Rcounter0);        
    currentdata = (Comm0Temp[16] - 48 )*1000 +(Comm0Temp[17] - 48)*100 + (Comm0Temp[19] - 48)*10 + (Comm0Temp[20] -48);    //获取液位数据
    Leveldata[datacount] = currentdata;

    if( datacount == 10)
    {
        datacount = 0;
        SumLevel = 0;

        for ( unsigned char i = 0;i < 10;i++)
        {
            SumLevel + = Leveldata[ i ];                                                  
        }

    AveLevel = SumLevel/10;    //数据处理部分,但是数据始终不对,放在中断里也不行
    }

}

出0入0汤圆

 楼主| 发表于 2012-10-11 09:08:07 | 显示全部楼层
我按照这个方法试过了,还是不行,接收到10个数据后仍然不做显示。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 07:13

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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