原创 通过写一个测速程序学到的!

2009-9-22 16:53 2183 7 7 分类: MCU/ 嵌入式
 



/*
* MCU:PIC18F458,该MCU的存储组织为线性,4K RAM,32K flash
* 主频:20M
* TMR0/TMR1/TMR3:输入为内部时间,5M
* TMR0:普通延时用
* TMR1:输出数据振荡器用
* TMR3:输入捕获用
*/


#include <pic18.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
__CONFIG(1,XT);
__CONFIG(2,WDTDIS);
__CONFIG(5,UNPROTECT);
//数字振荡器用变量
#define SAMPFREQ 8000
double m_fK;
double m_fX0;
double m_fX1;
double m_fX2;
double m_fSwing;
double m_fFrequency; //输出频率值
int    m_nFrequency;


#define SETUNIT 10
unsigned int m_nSetValue; // 额定值变量,开机时读入


volatile char m_bCapValue;
volatile unsigned long m_nOldCapValue;
volatile unsigned long m_nCapValue;
volatile unsigned int m_nCapHighWord;
volatile union
{
unsigned long m_nCapValue;
struct
{
   unsigned int w;
   unsigned char h;
   unsigned char l;
}Byte;
}CapValue;


volatile unsigned long m_nTick;


#define LIMIT 1000000
volatile unsigned long m_nOutTick;


///////////////////////////////////////////////////////////////


void interrupt PIC18F_isr(void);
void init(void);
void putch(unsigned char c);
void CalculateNextX(void);
void InitialKX(double fFrequency);
long Conv2Freq(long t);
void TestLimit(void);


///////////////////////////////////////////////////////////////


void interrupt PIC18F_isr(void)
{
if(TMR1IE && TMR1IF) /**/
{
   // 数字振荡器
   TMR1 += -625;    /*Load initial value to TIMER1*/                         
   TMR1IF=0;


   CalculateNextX();
   // 输出
   if(m_fX0 > 0)
    PORTC |= 0x02;
   else
    PORTC &= 0xfd;
    }


if(TMR3IE && TMR3IF) /**/
{
   if(m_nCapHighWord < 1000)
    m_nCapHighWord++;


   TMR3IF=0;
    }


if(CCP1IE && CCP1IF) /*interrupt from CCP1 has occured*/
{
   if(m_bCapValue == 0)
   {
    CapValue.Byte.l = CCPR1L;
    CapValue.Byte.h = CCPR1H;
    CapValue.Byte.w = m_nCapHighWord;
    TMR1 = 0x18;
    m_nCapHighWord = 0;


    m_nCapValue = CapValue.m_nCapValue;
    m_bCapValue = 1;
   }


   CCP1IF=0;
}


if(TMR0IE && TMR0IF) /**/
{
   // 1ms
   TMR0 -= 5000;   /*Load initial value to TIMER1*/
   m_nTick++;


   TestLimit(); // 限值检测
   if(m_nOutTick > LIMIT)
    PORTD &= 0x7f; // 超限输出
   else
    PORTD |= 0x80; // 复限


   TMR0IF=0;
    }
}


void init(void)
{
// 初始化捕获时间值缓冲区
m_bCapValue = 0;
m_nCapValue = 0x640000;
m_nOldCapValue = m_nCapValue;
m_nCapHighWord = 0;


m_fFrequency = (double)Conv2Freq(m_nCapValue) / 100;


// 振荡器初值
m_fX0 = 0;
m_fSwing = 1;
InitialKX(m_fFrequency);


T0CON = 0x88;   /*use TIMER0 */
TMR0 = -5000;   /*Load initial value to TIMER1 */
TMR0ON = 1;
TMR0IE = 1;


T1CON = 0x81;   /*use TIMER1 */
TMR1 = -625;   /*Load initial value to TIMER1*/
TMR1ON = 1;
TMR1IE = 1;


T3CON=0x88;   /*T3CON controls TIMER3 AND selects which timer is used for each CCP*/    
TMR3=0;    /*Load initial value to TIMER3*/    
TMR3ON=1;
TMR3IE = 1;


CCP1CON = 0x05; // CPP初始化代码,Capture mode, every 1th rising edge
CCP1IF=0;
CCP1IE = 1;


TRISA = 0xff;   /* RA0-RA5额定转速设置 */
TRISC = 0xfd;   /* RC2 OUT:1111 1101 */
TRISD = 0x7f;   /* RD7 OUT:0111 1111 */
PORTA = 0xff;
PORTB = 0xff;
PORTC = 0xff;
PORTD = 0xff;



SYNC = 0;   //Asynchronous mode
BRGH = 1;
SPBRG = 0x67; // baud rate="20M/16"(103+1)=2400


TXEN=1;    /* enable serial port transmissions */
SPEN=1;    
TXIE=0;    /* not interrupt driven */  


// 读取设值
m_nSetValue = PORTA;
m_nSetValue &= 0x1f;
m_fFrequency = (double)(m_nSetValue * SETUNIT) * 96.0F / 600.0F;
m_nSetValue = (int)(m_fFrequency * 100.0F);
InitialKX(m_fFrequency);


m_nTick = 0;
m_nOutTick = 0;


PEIE = 1;
GIE = 1;
}


void putch(unsigned char c)
{
TXREG = c;   /* transmit a character to Serial IO */
while(!TXIF)
   continue;
TXIF = 0;
}



void CalculateNextX(void)
{
// 数字振荡器
m_fX0 = m_fK * m_fX1 - m_fX2;
m_fX2 = m_fX1;
m_fX1 = m_fX0;
}


void InitialKX(double fFrequency)
{
// 数字振荡器
GIE = 0;
m_fK = 2.0F * cos(2.0F * 3.1415926F * fFrequency / SAMPFREQ);
m_fX2 = m_fSwing * sin(2.0F * 3.1415926F * fFrequency / SAMPFREQ);
m_fX1 = 0;
GIE = 1;
}


long Conv2Freq(long t)
{
// 5M
long nFreq = 500000000 / t;
if(nFreq > 9600)
   nFreq = 9600;


if(nFreq < 76)
   nFreq = 0;


return nFreq;
}



void TestLimit(void)
{
// 1ms执行一次
//
// 限值检测
// >=110%Ve---2s
// <110%Ve----x
// =Ve--------x
// >70%Ve-----x
// >50%Ve-----9s
// <50%Ve-----2s


static nACC = 0;


if(m_nFrequency >= m_nSetValue * 110 / 100)
{
   // >110%,2s
   m_nOutTick += LIMIT / 2000;
}
else if(m_nFrequency <= m_nSetValue * 50 / 100)
{
   // <50%,2s
   m_nOutTick += LIMIT / 2000;
}
else if((m_nFrequency > m_nSetValue * 50 / 100) && (m_nFrequency < m_nSetValue * 70 / 100))
{
   // <50%,2s
   m_nOutTick += LIMIT / 9000;
}
else
{
   // 50% < Ve < 70%
   m_nOutTick = 0;
}
}


void main(void)
{
init();
while(1)
{
   CLRWDT();


   if(m_nOldCapValue != m_nCapValue)
   {
    // 速度转换
    long nFreq = Conv2Freq(m_nCapValue); // 周期-->频率,单位0.01Hz
    m_fFrequency = (double)nFreq * 800.0F / 96.0F / 100.0F + 200.0F; // 转换为输出频率
    m_nFrequency = (int)(m_fFrequency * 100.0f);
    InitialKX(m_fFrequency);


    m_nOldCapValue = m_nCapValue;
   }
}
}


       下面这段是摘自《用定时器实现数字振荡器》作者李方健,讲了怎么样把数学理论结合定时系统用C语言实现数字振荡器的原理!详细讲解请看这篇期刊!


        假设信号为sin ( wt ) ,自变量t 代表模拟域。在数字域中,信号为sin ( w n T) , 其中w 是角频率, T 是采样周期, n是自然数。为了产生y ( n) = sin ( w n T) , 需要构建一个系统。假设一个数字系统,系统输入为δ( n) ,
δ( n)   0  n ≠0
           1  n = 0
系统输出为y ( n) = sin ( w n T) 。分别把输入和输出进行Z 变换,
Z[δ( n) ] = 1
Z[ y ( n) ] = Cz
z2 - A z - B
其中C = sin ( w T)  B = - 1  A = 2cos( w T)
从而,该数字系统的系统函数为
H( z ) = Z[ y ( n) ]
Z[δ( n) ]= Cz/(z2 - A z - B)
把该系统函数变换到时间域,得到系统差分方程y ( n) = A y ( n - 1) + By ( n - 2) + Cx ( n - 1)其中, x ( n) 是系统输入, y ( n) 是系统输出。把x ( n) =δ( n)代入上述差分方程,y (0) = 0  y (1) = C  y (2) = A y (1)
y ( n) = A y ( n - 1) + By ( n - 2)结论:在n > 2 以后, y ( n) 能用y ( n - 1) 和y ( n - 2) 就能算出,这是一个递归的差分方程。因此只要已知系统输出正弦信号角频率w 和系统采样周期T ,就可以得到输出y ( n) 的
差分方程。系统只需要每隔T 秒(通过定时器设置,每隔采样时间 中断一次) 计算一次差分方程,就可以得到当前输出正弦采样y ( n) = sin ( w n T) 。


总结一下:


1:精度要求。用浮点数来满足要求,在输入输出的时候因为MCU等位处理器只识别整型,即只识别0,1所以在输入输出的时候在把浮点数乘以需要的几位精度的倍数。扩大整数的范围来达到精度。剩下的由显示部分完成精度的显示。


2:注意单位。单位要统一,因为MCU等它只是处理数据的,它并不能识别单位。所以单位的转换要靠我们来把握。


3:数字振荡器。掌握数字振荡器的原理。因为它可以很容易实现频率的变换。这也是变频器的基本原理。

转载自:http://hi.baidu.com/xushixia55/blog/item/7c6e2efb13b7a01e6d22eb3d.html
PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
7
关闭 站长推荐上一条 /3 下一条