5iMX宗旨:分享遥控模型兴趣爱好

5iMX.com 我爱模型 玩家论坛 ——专业遥控模型和无人机玩家论坛(玩模型就上我爱模型,创始于2003年)
查看: 8300|回复: 64
打印 上一主题 下一主题

ppm信号怎么输入单片机啊 我都要哭了4

[复制链接]
跳转到指定楼层
楼主
发表于 2013-8-31 22:10 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
是这样的 我想把ppm信号输入单片机at89s52 可单片机的捕捉模块式沿下降沿触发 ppm信号式file:///C:\Users\Administrator\AppData\Roaming\Tencent\Users\934415937\QQ\WinTemp\RichOle\RKLH)~CQNIC5C)$_N_]%BDD.jpg上升沿信号 我加了反相器74hc04 也还是没用 怎么办 求高手指点 我用是用的网上的程序
//PPM 解码程序
//用INT0接PPM信号
//T0计数,用来测量脉宽
//注意,这个不是标准的PPM信号,刚好和PPM信号相位相反
//测得的PPM信号在LCD上显示
//PPM信号取自天地飞6A接收机
//时间:2012年2月15日0:22:31
# include <reg52.h>
# include <intrins.h>

# define DataPort P2

sbit RS=P0^5;
sbit RW=P0^6;
sbit EN=P0^7;

unsigned char channel=0,i=0;
unsigned int xdata PPM_channel1[10],PPM_channel2[10],PPM_channel3[10],PPM_channel4[10],PPM_channel5[10],PPM_channel6[10];
bit Timer0_OverFlowFlag=0;//定时器0的溢出标志,如果溢出,则有问题;
unsigned char qian,bai,shi,ge;

# define RS_CLR RS=0;
# define RS_SET RS=1;
# define RW_SET RW=1;
# define RW_CLR RW=0;
# define EN_CLR        EN=0;
# define EN_SET EN=1;

//和LCD显示有关的函数定义
void LCD_Check_Busy(void); //查忙函数
void LCD_Clear(void);//清屏函数
void LCD_Init(void);//lcd初始化函数
void LCD_Write_Com(unsigned char com);//控制字写入函数
void LCD_Write_Data(unsigned char Data);//数据写入函数
void LCD_Write_Char(unsigned char x,unsigned char y,unsigned char Data);//写入单个字符
void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s);//写入字符串
unsigned int filter(unsigned int *s);//中值平局滤波;
void DepartNum(unsigned int temp);//用于分解要显示的数据

void DelayUs2x(unsigned char t);
void DelayMs(unsigned int t);


void main(void)
{         
    unsigned char *InitIform;
        unsigned int temp;
        InitIform="Init_is_OK";
        LCD_Init();
        DelayMs(10);
        LCD_Write_String(3,0,InitIform);


//初始化Timer0
        TMOD=0x01;//timer0 方式1
        ET0=1;//允许timer0中断

//初始化INT0
        IT0=1;//负跳变触发中断;
        EX0=1;

        EA=1;
       
        DelayMs(10000);
        while(1)
        {
            temp=filter(PPM_channel1);
                DepartNum(temp);
                LCD_Write_Char(0,0,'A');
                LCD_Write_Char(1,0,qian);
                LCD_Write_Char(2,0,bai);
                LCD_Write_Char(3,0,shi);
                LCD_Write_Char(4,0,ge);

            temp=filter(PPM_channel2);                
                DepartNum(temp);
                LCD_Write_Char(5,0,'B');
                LCD_Write_Char(6,0,qian);
                LCD_Write_Char(7,0,bai);
                LCD_Write_Char(8,0,shi);
                LCD_Write_Char(9,0,ge);

            temp=filter(PPM_channel3);
                DepartNum(temp);
                LCD_Write_Char(10,0,'C');
                LCD_Write_Char(11,0,qian);
                LCD_Write_Char(12,0,bai);
                LCD_Write_Char(13,0,shi);
                LCD_Write_Char(14,0,ge);

            temp=filter(PPM_channel4);
                DepartNum(temp);
                LCD_Write_Char(0,1,'D');
                LCD_Write_Char(1,1,qian);
                LCD_Write_Char(2,1,bai);
                LCD_Write_Char(3,1,shi);
                LCD_Write_Char(4,1,ge);
               
            temp=filter(PPM_channel5);
                DepartNum(temp);
                LCD_Write_Char(5,1,'E');
                LCD_Write_Char(6,1,qian);
                LCD_Write_Char(7,1,bai);
                LCD_Write_Char(8,1,shi);
                LCD_Write_Char(9,1,ge);

            temp=filter(PPM_channel6);
                DepartNum(temp);
                LCD_Write_Char(10,1,'F');
                LCD_Write_Char(11,1,qian);
                LCD_Write_Char(12,1,bai);
                LCD_Write_Char(13,1,shi);
                LCD_Write_Char(14,1,ge);

//                DelayMs(1000);
        }
                                          
}


void DelayUs2x(unsigned char t)
{   
while(--t);
}

void DelayMs(unsigned int t)
{

while(t--)
{
     //大致延时1mS
     DelayUs2x(245);
         DelayUs2x(245);
}
}

//查忙函数
void LCD_Check_Busy(void)
{
unsigned char i=255;
DataPort= 0xff;
RS_CLR;
RW_SET;
EN_SET;
while(i--&&(DataPort&0x80));
EN_CLR;
}

//控制字写入函数,入口参数是控制字
void LCD_Write_Com(unsigned char com)
{
        LCD_Check_Busy();
        RS_CLR;
        RW_CLR;
        DataPort=com;
        EN_SET;
        _nop_();
        EN_CLR;
}

//写入数据,入口参数是要写入的数据
void LCD_Write_Data(unsigned char Data)
{
        LCD_Check_Busy();
        RS_SET;
        RW_CLR;
        DataPort=Data;
        EN_SET;
        _nop_();
        EN_CLR;       
}

//清屏函数
void LCD_Clear(void )
{
        LCD_Write_Com(0x01);
        DelayMs(5);               
}

//LCD显示字符串,入口参数是 字符显示的位置X(0-15),显示的行数y(0,1 ),*S显示的字符串
void LCD_Write_String(unsigned char x,unsigned char y, unsigned char *s)
{
        if(y==0) LCD_Write_Com(0x80+x);
        else LCD_Write_Com(0xc0+x);
        while(*s)
        {
                LCD_Write_Data(*s);
                s++;
        }
}

//LCD显示字符串,入口参数是 字符显示的位置X(0-15),显示的行数y(0,1 ),Data显示的字符
void LCD_Write_Char(unsigned char x,unsigned char y,unsigned char Data)
{
         if(y==0) LCD_Write_Com(0x80+x);
         else LCD_Write_Com(0xc0+x);
            DelayMs(1);//a little delay for simulation
         LCD_Write_Data(Data);
}


//lcd初始化函数
void LCD_Init(void)
{
        LCD_Write_Com(0x38);// set the display model
        DelayMs(5);
        LCD_Write_Com(0x08);//turn down the display
        //LCD_Write_Com(0x01);//clear the display
        LCD_Clear();
        LCD_Write_Com(0x06);//set the 光标 moving model
        DelayMs(5);
        LCD_Write_Com(0x0c);//显示开和光标设置
}

/****************************************
用于显示的数位分解函数,把数据转化为ASCII码
入口参数是要显示的数据
****************************************/
void DepartNum(unsigned int temp)
{
        qian=temp/1000+0x30;
        bai=temp%1000/100+0x30;
        shi=temp%100/10+0x30;
        ge= temp%10+0x30;
}

void ISIR_INT0(void) interrupt 0
{
        unsigned int PPM_temp;
        if(TR0)
        {
                TR0=0;//停止计数;
                PPM_temp=TH0;
                PPM_temp=(PPM_temp<<8)|TL0;
                TH0=0;
                TL0=0;
                TR0=1;//给TH0和TL0赋初值后重新启动定时器
        }
        else
        {
                TH0=0;//如果是第一次启动中断,则启动timer0
                TL0=0;
                TR0=1;
        }
        if(PPM_temp>3000|| Timer0_OverFlowFlag)//判断引导区
        {
                channel=0;
                Timer0_OverFlowFlag=0;
                i++;
                if(i==10) i=0;
        }
        switch(channel)
        {
        case 1: PPM_channel1=PPM_temp; break;
        case 2: PPM_channel2=PPM_temp; break;
        case 3: PPM_channel3=PPM_temp; break;
        case 4: PPM_channel4=PPM_temp; break;
        case 5: PPM_channel5=PPM_temp; break;
        case 6: PPM_channel6=PPM_temp; break;
        case 7: break;
        case 8: break;
        default:break;
        }
        channel++;
}

void ISIR_Timer0(void) interrupt 1
{
        Timer0_OverFlowFlag=1;
}

unsigned int filter(unsigned int *s)
{
        unsigned char k,j;
        unsigned int sum=0;
        unsigned int temp;
        for(k=0;k<9;k++)
                for(j=k+1;j<10;j++)          
                if(s[k]>s[j])
                {
                        temp=s[k];
                        s[k]=s[j];
                        s[j]=temp;
                }
        for(k=1;k<9;k++)
        sum+=s[k];
        sum=sum/8;
        return sum;
}





RKLH)~CQNIC5C)$_N_]%BDD.jpg (78.72 KB, 下载次数: 73)

RKLH)~CQNIC5C)$_N_]%BDD.jpg

欢迎继续阅读楼主其他信息

主题

  • 没有相关信息
  • 没有相关信息
  • 没有相关信息
沙发
发表于 2013-8-31 23:59 | 只看该作者
天文与数字

不懂路过....

话说arduino真简单个说,一个duration搞定
3
发表于 2013-9-1 00:42 | 只看该作者
最主要的是:你输入之后 想干什么、想得到什么?
4
发表于 2013-9-1 01:07 | 只看该作者
LCD有没有正确显示?上电开机的时候有没有显示InitIform?
先确定LCD显示无误,再把中断关掉,把temp赋固定值看能否正确显示,最后再看捕获和中断设置有没有问题,一个一个的排除。
5
发表于 2013-9-1 01:10 | 只看该作者
天书不懂....路过!
6
发表于 2013-9-1 14:52 | 只看该作者
只要懂原理即可,没必要搜网上的程序代码。
pcm信号示波器测量下即可获得,也就是20ms的方波,通道信号是1-2ms脉冲;
自己采集处理即可。
7
发表于 2013-9-1 16:05 | 只看该作者
中断第一次上升沿,记下此刻的值。第二次把中断换成下降沿使能。用二次得的值减第一次的值就得高电平的脉宽值了。
具体实现要一个模块的测试看功能有没有达到预期。
8
 楼主| 发表于 2013-9-2 10:04 | 只看该作者
caosix2 发表于 2013-9-1 00:42
最主要的是:你输入之后 想干什么、想得到什么?

输入ppm信号 单片机根据ppm信号的高电平时间 对应输出pwm信号 控制电机的加速和减速
9
 楼主| 发表于 2013-9-2 10:06 | 只看该作者
dolphintt920 发表于 2013-9-1 01:07
LCD有没有正确显示?上电开机的时候有没有显示InitIform?
先确定LCD显示无误,再把中断关掉,把temp赋固定 ...

显示的是Init_is_OK  程序该怎么改呢

10
 楼主| 发表于 2013-9-2 10:07 | 只看该作者
bugsplus 发表于 2013-9-1 14:52
只要懂原理即可,没必要搜网上的程序代码。
pcm信号示波器测量下即可获得,也就是20ms的方波,通道信号是1 ...

程序不会啊

11
 楼主| 发表于 2013-9-2 10:08 | 只看该作者
peng617580660 发表于 2013-9-1 16:05
中断第一次上升沿,记下此刻的值。第二次把中断换成下降沿使能。用二次得的值减第一次的值就得高电平的脉宽 ...

89s52是沿下降沿触发的啊 怎么记录他高电平时间 求个程序说明 怎么让他中断第一次上升沿


12
发表于 2013-9-2 10:55 | 只看该作者
普加乔夫 发表于 2013-9-2 10:04
输入ppm信号 单片机根据ppm信号的高电平时间 对应输出pwm信号 控制电机的加速和减速

你是在 自己做 “电调” 哦 !!

单片机 如果有 CCP 模块,就很简单:

直接用 CCP 捕捉模块 去测量 输入的脉冲宽度 Esay

13
发表于 2013-9-2 14:44 | 只看该作者
本帖最后由 peng617580660 于 2013-9-2 14:49 编辑
普加乔夫 发表于 2013-9-2 10:08
89s52是沿下降沿触发的啊 怎么记录他高电平时间 求个程序说明 怎么让他中断第一次上升沿

这样就用低电平触发,第一次来读外部脚电平。记录此时的时刻1(定时器),然后改为外部低电平触发中断,中断后记录时刻2,这样就得出高电平时刻了。当然软件里要切换这两种模式


另一种方式就是用定时器的输入捕获功能。
14
 楼主| 发表于 2013-9-2 17:44 | 只看该作者
caosix2 发表于 2013-9-2 10:55
你是在 自己做 “电调” 哦 !!

单片机 如果有 CCP 模块,就很简单:

at89s52没用cpp模块 这是个有刷电调 做出来

15
 楼主| 发表于 2013-9-2 17:45 | 只看该作者
peng617580660 发表于 2013-9-2 14:44
这样就用低电平触发,第一次来读外部脚电平。记录此时的时刻1(定时器),然后改为外部低电平触发中断,中 ...

能写点程序看看吗

16
发表于 2013-9-2 18:18 | 只看该作者
白的可以,只捕捉一个下降沿能测量脉宽吗?用膝盖想想
17
发表于 2013-9-2 18:19 | 只看该作者
普加乔夫 发表于 2013-9-2 17:44
at89s52没用cpp模块 这是个有刷电调 做出来

用C8051F系列
很牛X的片子

18
发表于 2013-9-3 11:08 | 只看该作者
普加乔夫 发表于 2013-9-2 17:45
能写点程序看看吗


    if(引脚电平==0)
    {
        oldTime = newTime;
    }
    else
    {
            tmp = newTime - oldTime;                             
        if((tmp >= downData) && (tmp <= upData))            
        {
             有效数据;   
        }        
    }

newTime 当前定时器的值
oldTime  上一次的值


开个定时器就行了,不用外部中断貌似也可以。


19
发表于 2013-9-6 16:48 | 只看该作者
这个片子不能上升沿中断,可以加个异或门,这样上升沿下降沿都可以中断了;
两次中断的时间差就是脉宽;
20
 楼主| 发表于 2013-9-6 23:04 | 只看该作者
bugsplus 发表于 2013-9-6 16:48
这个片子不能上升沿中断,可以加个异或门,这样上升沿下降沿都可以中断了;
两次中断的时间差就是脉宽;

我加了个74ch04
您需要登录后才可以回帖 登录 | 我要加入

本版积分规则

关闭

【站内推荐】上一条 /2 下一条

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