|
本帖最后由 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, 杜汶泽)
|