mega16外围连接如下:相位差脉冲信号从PD6口输入,相位差关系判断信号从PD7口输入(前面整形电路已将两路同频输入信号处理成相位差脉冲信号和判断信号);如果判断信号是高电平,则显示“超前”,否则为“滞后”。
AVR与LCD1602连接信息
PA1 ->RS
PA3 ->EN
地 ->RW
PA4 ->D4
PA5 ->D5
PA6 ->D6
PA7 ->D7
与键盘连接:
PB4->key1
PB5->key2
PB6->key3
PB7->key4
我的思路是用PD6的输入捕获功能,分别设置上升沿和下降沿触发来计时,脉冲信号的上升沿和下降沿之间是脉冲宽度,上升沿和上升沿之间是周期,两者之比再乘以360就是相位差。
此原理是否可行,精度如何、
然后参考了网上的程序(网上的程序是测占空比和周期的,我觉得原理相同),将之修改了下,发现无法正确测周期和占空比,更不用说相位差了。因为本人单片机学得不怎么好,特来向各位求助!如得帮助,感激不尽~
这个相位计最终做成的效果是这样的:实时测量,每隔一秒刷新显示信息;在1602上第一行显示相位差,第二行显示相位关系,按key1能切换成显示输入信号的周期。请问各位如何实现程序?
看看程序的问题?是否有更好的方法?
-------------------------------------------------------------------------------------------------------------
主程序如下:main.c
#include
#include
#include "1602.h"
#include "delay.h"
#pragma data:data //可以省略
unsigned char Data1[6]={0,0,0,'.',0,0};//周期数据
unsigned char Data2[6]={0,0,0,'.',0,0};//相位差数据
unsigned char num=0;//判断是前半周期还是后半周期
unsigned int hightime, lowtime, space, totaltime;
// 前半周期时间,后半周期时间,占空比,周期
#define icp_low() TCCR1B&=~(1<
#define icp_High() TCCR1B|=(1<
//ICP捕获中断程序
#pragma interrupt_handler Icp_timer1:6
void Icp_timer1(void)
{
num++;
if(num%2)//判断区分是前半周期还是后半周期
{
lowtime=ICR1;////记后前半周期时间
ICR1=0;//ICR1清零
TCNT1=0;//计数器清零
icp_low();//改变触发方式为下降沿触发
}
else
{
hightime=ICR1;//记下前半周期时间
ICR1=0;//ICR1清零
TCNT1=0;//计数器清零
icp_High();//改变触发方式为上升沿触发
}
}
//端口初始化
void port_int(void)
{
DDRA=0XFF;
PORTA=0XFF;
DDRD=0X3F;//ICP脚为输入
DDRB=0XFF;
PORTD=0XFF;//初始化为高电平
PORTB=0XFF;
}
void timer1_int(void)//定时器1初始化
{
TIMSK=0X20;
TCCR1A=0X00;
TCCR1B=0XC2;//噪声抑制,捕获中断,8分频
ICR1=0;//ICR1清零
TCNT1=0;//计数器清零
icp_High();//初始化上升沿触发
}
void init(void)
{
port_int();
timer1_int();
}
//主程序:测量ICP引脚上信号的周期
void main(void)
{
unsigned char num2;
init();
SREG|=0X80;
LCD_init();//1602初始化
while(1)
{
totaltime=lowtime+hightime;//周期
space=(hightime)*100/totaltime; //占空比
SEI();//开全局中断
delay_nms(1);//这里延时限制了接收周期最大为1ms的方波
CLI(); //禁止所有中断
//下面的是1602显示
chuli(totaltime,Data1);
chuli(space,Data2);
LCD_write_string(0,0,"Cycle:");
LCD_write_string(8,0,Data1);
LCD_write_string(14,0,"us");
LCD_write_string(0,1,"space:");
LCD_write_string(8,1,Data2);
LCD_write_string(14,1,"%");
}
}
void chuli(unsigned int i,unsigned char *p) //显示处理,+48是因为液晶显示的是ASCII码
{
p[0]=i/1000%10+48;//百
i = i % 1000;
p[1]=i/100%10+48;//十
i = i % 100;
p[2]=i/10%10+48;//个
p[4]=i%10+48;//小数点后一位
}
------------------------------------------------------------------------------------------------------
1602.h
/* 用法:
LCD_init();
LCD_write_string(列,行,"字符串");
LCD_write_char(列,行,'字符');
---------------------------------------------------------------
下面是AVR与LCD连接信息
PA1 ->RS
PA3 ->EN
地 ->RW
PA4 ->D4
PA5 ->D5
PA6 ->D6
PA7 ->D7
要使用本驱动,改变下面配置信息即可
-----------------------------------------------------------------*/
#define LCD_EN_PORT PORTA //以下2个要设为同一个口
#define LCD_EN_DDR DDRA
#define LCD_RS_PORT PORTA //以下2个要设为同一个口
#define LCD_RS_DDR DDRA
#define LCD_DATA_PORT PORTA //以下3个要设为同一个口
#define LCD_DATA_DDR DDRA //默认情况下连线必须使用高四位端口,如果不是请注意修改
#define LCD_DATA_PIN PINA
#define LCD_RS (1<
#define LCD_EN (1<
#define LCD_DATA ((1<
/*--------------------------------------------------------------------------------------------------
函数说明
--------------------------------------------------------------------------------------------------*/
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);
//-----------------------------------------------------------------------------------------
#include
#include "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_nms(2);
}
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) //写指令
{
//连线为高4位的写法
delay_nus(16);
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();
/*
//连线为低四位的写法
delay_nus(16);
LCD_RS_PORT&=~LCD_RS; //RS=0
LCD_DATA_PORT&=0xf0; //清高四位
LCD_DATA_PORT|=(command>>4)&0x0f; //写高四位
LCD_en_write();
LCD_DATA_PORT&=0xf0; //清高四位
LCD_DATA_PORT|=command&0x0f; //写低四位
LCD_en_write();
*/
}
void LCD_write_data(unsigned char data) //写数据
{
//连线为高4位的写法
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();
/*
//连线为低四位的写法
delay_nus(16);
LCD_RS_PORT|=LCD_RS; //RS=1
LCD_DATA_PORT&=0Xf0; //清高四位
LCD_DATA_PORT|=(data>>4)&0x0f; //写高四位
LCD_en_write();
LCD_DATA_PORT&=0Xf0; //清高四位
LCD_DATA_PORT|=data&0x0f; //写低四位
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);
-------------------------------------------------------------------------------------------------------------
/*-----------------------------------------------------------------------
延时函数
编译器:ICC-AVR v6.31A
目标芯片 : M16
时钟: 8.0000Mhz
-----------------------------------------------------------------------*/
#ifndef __delay_h
#define __delay_h
void delay_nus(unsigned int n);
void delay_nms(unsigned int n);
void delay_1us(void);
void delay_1ms(void) ;
void delay_1us(void) //1us延时函数
{
asm("nop");
}
void delay_nus(unsigned int n) //N us延时函数
{
unsigned int i=0;
for (i=0;i
delay_1us();
}
void delay_1ms(void) //1ms延时函数
{
unsigned int i;
for (i=0;i<1140;i++);
}
void delay_nms(unsigned int n) //N ms延时函数
{
unsigned int i=0;
for (i=0;i
delay_1ms();
}
#endif