业余研究嵌入式,现在这方面还是个门外汉,买了块Atmega128a的开发版和HC-SR04,慢慢跟着入门,今天做了个测距程序,一些知识点记录下来,怕以后给忘了。
晶震:8MHz
管脚连接: PD5接的HC-SR04的Trig,PD4接的HC-SR04的Echo
代码里的printf是我自己实现的一个版本,往串口输出,方便上位机测试
#include<avr/io.h>
#include<avr/interrupt.h>
#include "rs232.h"
int lastValue, value;//分别记录上升沿和下降沿时的计数器值
enum {
READY,
STARTED,
COUNTING
}stage;
void initIO()
{
DDRD = (1<<PD5);//PD5设置为输出管脚
PORTD = 0x0;
}
void initTimer()
{
//初始化16位记时器
TCNT1 = 0;
TCCR1A |= 0x00;
TCCR1B |= 0x42;//使用普通模式(WGM),8分频(CS),使用上升沿触发输入捕捉(ICES1)
TIMSK = 0x20;//设置TICIE1为1,设置输入捕捉中断使能信号
}
//输入捕捉中断程序
ISR(TIMER1_CAPT_vect)
{
if(TCCR1B & 0x40)//捕捉到了上升沿
{
lastValue = ICR1;//记录上升沿的时候的计数器值
stage = COUNTING;//设置状态为正在记录
TCCR1B &= ~0x40;//让记时器捕捉下降沿
}
else
{
value = ICR1;//记录下降沿的时候的计数器值
stage = READY;//标记为结束
TCCR1B |= 0x40;//让记时器捕捉上升沿
}
}
void delay(int n)
{
int i, j, k;
for(k = 0; k < n; k++)
for(i = 0; i < 100;i++)
for(j = 0; j < 500;j++)
asm("nop");
}
void send()
{
unsigned char k;
stage = STARTED;
lastValue = value = 0;
PORTD |= (1<<PD5);//将Trig信号设置为高电平一段时间后还原成低电瓶,这样会让超声波模块发送超声波并接受超声波
for(k= 0; k< 100;k++)
asm("nop");
PORTD &= ~(1<<PD5);
while(stage != READY);//等待接收结束
int time;
if(value < lastValue)//需要处理计数器向上溢出的情况,求出正确的时间差
time = 0xffff - lastValue + 1 + value;
else//没有溢出,直接求时间差
time = value - lastValue;
int distance = time / 58;//计算距离,单位cm
printf("done, distance = %dcm\r\n", distance);//输出结果
}
//禁用看门狗
void disableWatchdog()
{
asm("wdr");
WDTCR = (1 << WDCE) | (1<< WDE);
WDTCR = 0;//按照Atmega128a手册说法,关闭开门狗必须连续执行这三个代码才能正确关闭。
}
void main(void)
{
disableWatchdog();
initIO();
initTimer();
USART0_Init(); //波特率9600 初始化串口
SREG = 0x80;
asm("sei");
printf("\r\nSystem started, pause for 1s %d\r\n", MCUCSR);
delay(10);
while(1)
{
printf("Send trig...");
send();
delay(80);
}
}
今天困扰我的地方有几个知识点:
1)配饰TIMSK后导致系统执行玩第一个send后就自动复位,于是我试图关闭看门狗,但是关闭后还是自动复位,于是我用MCUCSR寄存器来调试复位原因,MCUCSR值是PORF|EXTRF,分别表示上电复位和外部复位,最初怀疑是电路板没接好,调试好久才发现我启用的是Timer1输入捕捉中断,而代码里原来是定义的Timer0溢出中断,因此中断向量表里输入捕捉中断那里指向的是0,导致发生中断的时候复位了
2)Magic Number 58,这个值是在HC-SR04资料里的51例子里看到的,但是解释得不够合理,然后在研究了AVR 16位定时器的普通模式后终于算出来,晶震是8MHz,8分频后,Timer1的时钟信号频率只有8MHz/8=1MHz,因此周期只有1/1MHz=1e-06,声音速度是344米,Echo高电平持续时间包括了发送和接受,因此距离 D=COUNT * 1e-06s * 344m/s /2 = COUNT/(58.13953488372093cm),最初推倒这个系数的时候,看书上说时钟记时器要超过TOP才会触发一次中断,16位Timer1的TOP为0xFFFF,所以我想着这个TOP是否也需要加入计算,这个也耗费了不少时间,最后才明白这个可以无视。
接下来研究Zigbee看怎么搞
Last modified on 2013-04-13