大家好!如何实现曼码的解码欢迎大家共同交流学习
曼码时序图本帖最后由 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);
} 如果 干扰不严重 可以用SPI
http://www.amobbs.com/thread-5518636-1-1.html 输入捕获,中断计时,不要用软件延时 skynet 发表于 2013-3-7 11:36 static/image/common/back.gif
输入捕获,中断计时,不要用软件延时
你好,请问输入捕捉如何实现下降沿和上升沿翻转计时? badhtnnw88 发表于 2013-3-7 11:44 static/image/common/back.gif
你好,请问输入捕捉如何实现下降沿和上升沿翻转计时?
边沿中断,只有上或下沿的,反相再叠加。 babysnail 发表于 2013-3-7 12:05 static/image/common/back.gif
边沿中断,只有上或下沿的,反相再叠加。
babysnail 你好,本人愚笨,是否须要加再一个中断函数进行翻转? 下面的程序是用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++;
//添加须要中断处理和程序
} 此段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 static/image/common/back.gif
仿真电路
运行时的效果
本想用来测量高电平与低电平的数值,搞了一两天,没搞出来 本帖最后由 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 xsh2005105326 发表于 2013-3-7 14:03 static/image/common/back.gif
AVR的单片机,利用边沿触发功能,轮流切换为上、下降沿触发,具体是什么触发,可以软件读取IO状态判定。
...
这样不行,因为你不知道是哪个沿。但是可以把输入信号接到两个IO上,一个上升沿一个下降沿,哪个先触发就是哪个电平。 wye11083 发表于 2013-3-7 14:10 static/image/common/back.gif
这样不行,因为你不知道是哪个沿。但是可以把输入信号接到两个IO上,一个上升沿一个下降沿,哪个先触发就 ...
当你进入ICP中断后读取ICP引脚状态,为“1”,说明是上升沿,为“0”则为下降沿。边沿触发选择位在进入中断后取反,这样就能实现上下降沿的切换。我几年前就已经实现这功能了,用来解码315 wye11083 发表于 2013-3-7 14:10 static/image/common/back.gif
这样不行,因为你不知道是哪个沿。但是可以把输入信号接到两个IO上,一个上升沿一个下降沿,哪个先触发就 ...
wye11083说的这个办法想我之前过{:tongue:} 但占用I/O口资源,大家看看能不能有更好的办法实现曼码解码{:smile:} xsh2005105326 发表于 2013-3-7 14:33 static/image/common/back.gif
当你进入ICP中断后读取ICP引脚状态,为“1”,说明是上升沿,为“0”则为下降沿。边沿触发选择位在进入中 ...
xsh2005105326{:lol:} 说的办法有道理,得试试 捕捉翻转必须定义一个位变量,AVR内部怎么实现位变量啊?和51大有不同,C语言中好像没有位操作,那位高人指点指点 原来很简单
在捕捉中断函数直接加上这一句,
TCCR1B^=(1<<ICES1); //每次捕捉改变一次触发方式
原本以为GCC与ICC不能这样操作寄存器位的,动手后才知道,有时候是自己想得太复杂了,为此总结了一点对于初学者不懂的先不要去研究,先实践再研究想到什么点子就怎么去做,这种效果比你看别人的代码受益得多, 可以直接用定时器直接算就好,你接收的数据一般都有sof+data+eof,那个在sof以后开始定时,定时器溢出的时间内,假如有电平的变化,那么你就可以判断0和1了
页:
[1]