搜索
bottom↓
回复: 18

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

[复制链接]

出0入0汤圆

发表于 2013-3-7 11:23:00 | 显示全部楼层 |阅读模式
曼码时序图

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

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

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

出0入0汤圆

 楼主| 发表于 2013-3-7 11:25:34 | 显示全部楼层
本帖最后由 badhtnnw88 于 2013-3-7 11:29 编辑

先给出一个自己写的曼码编码程序,
本人只是菜鸟,如有不对希望大家批评指正
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);
         
}

出0入0汤圆

发表于 2013-3-7 11:29:15 | 显示全部楼层
如果 干扰不严重 可以用SPI
http://www.amobbs.com/thread-5518636-1-1.html

出0入12汤圆

发表于 2013-3-7 11:36:12 | 显示全部楼层
输入捕获,中断计时,不要用软件延时

出0入0汤圆

 楼主| 发表于 2013-3-7 11:44:22 | 显示全部楼层
skynet 发表于 2013-3-7 11:36
输入捕获,中断计时,不要用软件延时

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

出0入0汤圆

发表于 2013-3-7 12:05:16 | 显示全部楼层
badhtnnw88 发表于 2013-3-7 11:44
你好,请问输入捕捉如何实现下降沿和上升沿翻转计时?

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

出0入0汤圆

 楼主| 发表于 2013-3-7 13:29:24 | 显示全部楼层
babysnail 发表于 2013-3-7 12:05
边沿中断,只有上或下沿的,反相再叠加。

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

出0入0汤圆

 楼主| 发表于 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[6]={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[4]=i%10+48;                        //个
        p[3]=i/10%10+48;                //十
        p[2]=i/100%10+48;                //百
        p[1]=i/1000%10+48;                //千
        p[0]=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++;
        //添加须要中断处理和程序
}

出0入0汤圆

 楼主| 发表于 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_PORT  PORTA   //以下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(unsigned  char 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);
        }
}

出0入0汤圆

 楼主| 发表于 2013-3-7 13:38:43 | 显示全部楼层
仿真电路

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2013-3-7 13:53:19 | 显示全部楼层
badhtnnw88 发表于 2013-3-7 13:38
仿真电路

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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2013-3-7 14:03:14 | 显示全部楼层
本帖最后由 xsh2005105326 于 2013-3-7 14:05 编辑
badhtnnw88 发表于 2013-3-7 11:44
你好,请问输入捕捉如何实现下降沿和上升沿翻转计时?


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

出0入442汤圆

发表于 2013-3-7 14:10:46 | 显示全部楼层
xsh2005105326 发表于 2013-3-7 14:03
AVR的单片机,利用边沿触发功能,轮流切换为上、下降沿触发,具体是什么触发,可以软件读取IO状态判定。
...

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

出0入0汤圆

发表于 2013-3-7 14:33:42 | 显示全部楼层
wye11083 发表于 2013-3-7 14:10
这样不行,因为你不知道是哪个沿。但是可以把输入信号接到两个IO上,一个上升沿一个下降沿,哪个先触发就 ...


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

出0入0汤圆

 楼主| 发表于 2013-3-7 14:40:35 | 显示全部楼层
wye11083 发表于 2013-3-7 14:10
这样不行,因为你不知道是哪个沿。但是可以把输入信号接到两个IO上,一个上升沿一个下降沿,哪个先触发就 ...

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

出0入0汤圆

 楼主| 发表于 2013-3-7 14:45:23 | 显示全部楼层
xsh2005105326 发表于 2013-3-7 14:33
当你进入ICP中断后读取ICP引脚状态,为“1”,说明是上升沿,为“0”则为下降沿。边沿触发选择位在进入中 ...

xsh2005105326 说的办法有道理,得试试

出0入0汤圆

 楼主| 发表于 2013-3-8 09:34:14 | 显示全部楼层
捕捉翻转必须定义一个位变量,AVR内部怎么实现位变量啊?和51大有不同,C语言中好像没有位操作,那位高人指点指点

出0入0汤圆

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

出0入0汤圆

发表于 2013-3-12 23:41:58 | 显示全部楼层
可以直接用定时器直接算就好,你接收的数据一般都有sof+data+eof,那个在sof以后开始定时,定时器溢出的时间内,假如有电平的变化,那么你就可以判断0和1了
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-7-24 03:21

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

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