badhtnnw88 发表于 2013-3-7 11:23:00

大家好!如何实现曼码的解码欢迎大家共同交流学习

曼码时序图

badhtnnw88 发表于 2013-3-7 11:25:34

本帖最后由 badhtnnw88 于 2013-3-7 11:29 编辑

先给出一个自己写的曼码编码程序,{:smile:}
本人只是菜鸟,如有不对希望大家批评指正
void bit_dat0()          //曼彻斯特编码1
{
        DS=0;
        dali_delayus(420);
        DS=1;
        dali_delayus(420);
        out=1;
}
void bit_dat1()          //曼彻斯特编码0
{
        DS=1;
        dali_delayus(420);
        DS=0;
        dali_delayus(420);
        out=0;
}
void write_command_DATE(unsigned char dat_addR,unsigned dat)
{          unsigned char i;
                dali_delayus(420);
                dali_delayus(420);
                dali_delayus(420);
                dali_delayus(420);
          bit_dat0();//start超始码
          for(i=0;i<8;i++)                //地址码adderss                  
          {
                  if((dat_addR&0x80)==0x80)
                          bit_dat0();       
                        else
                        {        bit_dat1();       }
                                dat_addR<<=1;
          }
          for(i=0;i<8;i++)                        //数据码data
          {
                  if((dat&0x80)==0x80)
                  bit_dat0();
                        else
                        {        bit_dat1();          }
                                dat<<=1;
          }
          DS=1;                  //停止码stop
          dali_delayus(420);
          dali_delayus(420);
          dali_delayus(420);
          dali_delayus(420);
       
}

xivisi 发表于 2013-3-7 11:29:15

如果 干扰不严重 可以用SPI
http://www.amobbs.com/thread-5518636-1-1.html

skynet 发表于 2013-3-7 11:36:12

输入捕获,中断计时,不要用软件延时

badhtnnw88 发表于 2013-3-7 11:44:22

skynet 发表于 2013-3-7 11:36 static/image/common/back.gif
输入捕获,中断计时,不要用软件延时

你好,请问输入捕捉如何实现下降沿和上升沿翻转计时?

babysnail 发表于 2013-3-7 12:05:16

badhtnnw88 发表于 2013-3-7 11:44 static/image/common/back.gif
你好,请问输入捕捉如何实现下降沿和上升沿翻转计时?

边沿中断,只有上或下沿的,反相再叠加。

badhtnnw88 发表于 2013-3-7 13:29:24

babysnail 发表于 2013-3-7 12:05 static/image/common/back.gif
边沿中断,只有上或下沿的,反相再叠加。

babysnail 你好,本人愚笨,是否须要加再一个中断函数进行翻转?

badhtnnw88 发表于 2013-3-7 13:31:51

下面的程序是用1602液晶显示器显示ICR1的计算
希望懂的朋友帮忙解答一下
#include<avr/io.h>
#include<util/delay.h>
#include<avr/interrupt.h>
#include"1602.c"
unsigned int Flag,Flag1;
unsigned char Data={0,0,0,0,0,0};//初始值为0000,最后一个0是结束符
unsigned int Counter;        //计数
unsigned int u;

void change(unsigned int i,unsigned char *p)        //显示处理,,+48是因为液晶显示的是ASCII码
{
        p=i%10+48;                        //个
        p=i/10%10+48;                //十
        p=i/100%10+48;                //百
        p=i/1000%10+48;                //千
        p=i/10000%10+48;        //万
}

unsigned int ICR1_convert(void)        //读取ICR1寄存器的转换函数
{
        unsigned int temp1,temp2,temp3;
        temp1=(unsigned int)ICR1L;
        temp2=(unsigned int)ICR1H;
        temp3=temp2;
        temp2=0.1/(0.001*temp3);
        return temp2;
}

void interrupt_init(void)
{
        //定时器/计数器0中断初始化
        TIMSK|=(1<<TICIE1)|(1<<TOIE0);
        TCCR0|=(1<<CS00);        //工作于普通模式,不分频
                                                //定时器频率=8M/1=8000000
        TCNT0=255;        //初值设置,定时间=(256-255)/8000000=0.125us
       
        //定时器/计数器1捕捉中断初始化
        TCCR1B|=(1<<ICNC1)|(1<<CS10)|(1<<CS12);        //开启捕捉噪声抑制器,下降沿方式
        //TCCR1B|=(1<<ICNC1)|(1<<CS00)|(1<<CS10)|(1<<CS12);        //开启捕捉噪声抑制器,上升沿方式
        TIMSK|=(1<<TICIE1);                        //T/C1溢出中断允许
}
int main(void)
{        unsigned int i;
        PORTB=0X00;
        DDRB=0XFF;
        PORTD=0X40;
        DDRD=0Xbf;
        LCD_init();
        interrupt_init();
        sei();
        while(1)
        {
               
                change(u,Data);
                LCD_write_string(4,0,"LOW_");
                LCD_write_string(8,0,Data);
               
                i=ICR1_convert();        //将转换赋给i
                change(i,Data);
                LCD_write_string(3,1,"HIGH_");
                LCD_write_string(8,1,Data);
               
        }
}

ISR(TIMER1_CAPT_vect)                //定时器/计数器1捕捉中断//每一次下降沿执行一次下面的语句
{
        TCNT1=0;                //清零计数寄存器
        u=Counter;
        Counter=0;
        //添加须要中断处理的程序
}

SIGNAL(TIMER0_OVF_vect)                //定时器计数器2溢出中断
{
        TCNT0=255;
        Counter++;
        //添加须要中断处理和程序
}

badhtnnw88 发表于 2013-3-7 13:34:02

此段1602显示代码引用来自本论坛
//************1602.C*************//
/* 用法:
   LCD_init();
   LCD_write_string(列,行,"字符串");
   LCD_write_char(列,行,'字符');
---------------------------------------------------------------
下面是AVR与LCD连接信息
PA2 ->RS
PA3 ->EN
地->RW
PA4 ->D4
PA5 ->D5
PA6 ->D6
PA7 ->D7
要使用本驱动,改变下面配置信息即可
-----------------------------------------------------------------*/
#define LCD_EN_PORT    PORTC   //以下2个要设为同一个口
#define LCD_EN_DDR   DDRC
#define LCD_RS_PORT    PORTC   //以下2个要设为同一个口
#define LCD_RS_DDR   DDRC
#define LCD_DATA_PORTPORTA   //以下3个要设为同一个口
#define LCD_DATA_DDR   DDRA    //一定要用高4位
#define LCD_DATA_PIN   PINA
#define LCD_RS         (1<<PC6) //0x04   portC6       out
#define LCD_EN         (1<<PC7) //0x08   portC7       out
#define LCD_DATA       ((1<<PA4)|(1<<PA5)|(1<<PA6)|(1<<PA7)) //0xf0   portA4/5/6/7 out
/*--------------------------------------------------------------------------------------------------
函数说明
--------------------------------------------------------------------------------------------------*/
void LCD_init(void);
void LCD_en_write(void);
void LCD_write_command(unsignedchar command) ;
void LCD_write_data(unsigned char data);
void LCD_set_xy (unsigned char x, unsigned char y);
void LCD_write_string(unsigned char X,unsigned char Y,unsigned char *s);
void LCD_write_char(unsigned char X,unsigned char Y,unsigned char data);
void delay_nus(unsigned int lus);
//-----------------------------------------------------------------------------------------

#include <avr/io.h>
#include<util/delay.h>
void LCD_init(void)         //液晶初始化
{
LCD_DATA_DDR|=LCD_DATA;   //数据口方向为输出
LCD_EN_DDR|=LCD_EN;       //设置EN方向为输出
LCD_RS_DDR|=LCD_RS;       //设置RS方向为输出
LCD_write_command(0x28);
LCD_en_write();
delay_nus(40);
LCD_write_command(0x28);//4位显示
LCD_write_command(0x0c);//显示开
LCD_write_command(0x01);//清屏
delay_nus(200);
}

void LCD_en_write(void)//液晶使能
{
LCD_EN_PORT|=LCD_EN;
delay_nus(1);
LCD_EN_PORT&=~LCD_EN;
}

void LCD_write_command(unsigned char command) //写指令
{
delay_nus(10);
LCD_RS_PORT&=~LCD_RS;      //RS=0
LCD_DATA_PORT&=0X0f;         //清高四位
LCD_DATA_PORT|=command&0xf0; //写高四位
LCD_en_write();
command=command<<4;          //低四位移到高四位
LCD_DATA_PORT&=0x0f;         //清高四位
LCD_DATA_PORT|=command&0xf0; //写低四位
LCD_en_write();

}

void LCD_write_data(unsigned char data) //写数据
{
delay_nus(16);
LCD_RS_PORT|=LCD_RS;       //RS=1
LCD_DATA_PORT&=0X0f;       //清高四位
LCD_DATA_PORT|=data&0xf0;//写高四位
LCD_en_write();
data=data<<4;               //低四位移到高四位
LCD_DATA_PORT&=0X0f;      //清高四位
LCD_DATA_PORT|=data&0xf0;   //写低四位
LCD_en_write();
}


void LCD_set_xy( unsigned char x, unsigned char y )//写地址函数
{
    unsigned char address;
    if (y == 0) address = 0x80 + x;
    else   address = 0xc0 + x;
    LCD_write_command( address);
}

void LCD_write_string(unsigned char X,unsigned char Y,unsigned char *s) //列x=0~15,行y=0,1
{
    LCD_set_xy( X, Y ); //写地址   
    while (*s)// 写显示字符
    {
      LCD_write_data( *s );
      s ++;
    }
      
}

void LCD_write_char(unsigned char X,unsigned char Y,unsigned char data) //列x=0~15,行y=0,1
{
LCD_set_xy( X, Y ); //写地址
LCD_write_data( data);

}

void delay_nus(unsigned int lus)
{
        while(lus--)
        {
                _delay_loop_2(30);
        }
}

badhtnnw88 发表于 2013-3-7 13:38:43

仿真电路

badhtnnw88 发表于 2013-3-7 13:53:19

badhtnnw88 发表于 2013-3-7 13:38 static/image/common/back.gif
仿真电路

运行时的效果
本想用来测量高电平与低电平的数值,搞了一两天,没搞出来

xsh2005105326 发表于 2013-3-7 14:03:14

本帖最后由 xsh2005105326 于 2013-3-7 14:05 编辑

badhtnnw88 发表于 2013-3-7 11:44 static/image/common/back.gif
你好,请问输入捕捉如何实现下降沿和上升沿翻转计时?

AVR的单片机,利用边沿触发功能,轮流切换为上、下降沿触发,具体是什么触发,可以软件读取IO状态判定。
我N年前做的,可以参考下,帖子地址:http://www.amobbs.com/thread-3910642-1-1.html

wye11083 发表于 2013-3-7 14:10:46

xsh2005105326 发表于 2013-3-7 14:03 static/image/common/back.gif
AVR的单片机,利用边沿触发功能,轮流切换为上、下降沿触发,具体是什么触发,可以软件读取IO状态判定。
...

这样不行,因为你不知道是哪个沿。但是可以把输入信号接到两个IO上,一个上升沿一个下降沿,哪个先触发就是哪个电平。

xsh2005105326 发表于 2013-3-7 14:33:42

wye11083 发表于 2013-3-7 14:10 static/image/common/back.gif
这样不行,因为你不知道是哪个沿。但是可以把输入信号接到两个IO上,一个上升沿一个下降沿,哪个先触发就 ...

当你进入ICP中断后读取ICP引脚状态,为“1”,说明是上升沿,为“0”则为下降沿。边沿触发选择位在进入中断后取反,这样就能实现上下降沿的切换。我几年前就已经实现这功能了,用来解码315

badhtnnw88 发表于 2013-3-7 14:40:35

wye11083 发表于 2013-3-7 14:10 static/image/common/back.gif
这样不行,因为你不知道是哪个沿。但是可以把输入信号接到两个IO上,一个上升沿一个下降沿,哪个先触发就 ...

wye11083说的这个办法想我之前过{:tongue:} 但占用I/O口资源,大家看看能不能有更好的办法实现曼码解码{:smile:}

badhtnnw88 发表于 2013-3-7 14:45:23

xsh2005105326 发表于 2013-3-7 14:33 static/image/common/back.gif
当你进入ICP中断后读取ICP引脚状态,为“1”,说明是上升沿,为“0”则为下降沿。边沿触发选择位在进入中 ...

xsh2005105326{:lol:} 说的办法有道理,得试试

badhtnnw88 发表于 2013-3-8 09:34:14

捕捉翻转必须定义一个位变量,AVR内部怎么实现位变量啊?和51大有不同,C语言中好像没有位操作,那位高人指点指点

badhtnnw88 发表于 2013-3-8 11:37:30

原来很简单
在捕捉中断函数直接加上这一句,
TCCR1B^=(1<<ICES1);        //每次捕捉改变一次触发方式
原本以为GCC与ICC不能这样操作寄存器位的,动手后才知道,有时候是自己想得太复杂了,为此总结了一点对于初学者不懂的先不要去研究,先实践再研究想到什么点子就怎么去做,这种效果比你看别人的代码受益得多,

三春虫 发表于 2013-3-12 23:41:58

可以直接用定时器直接算就好,你接收的数据一般都有sof+data+eof,那个在sof以后开始定时,定时器溢出的时间内,假如有电平的变化,那么你就可以判断0和1了
页: [1]
查看完整版本: 大家好!如何实现曼码的解码欢迎大家共同交流学习