按下3秒钟,如何使用Atmega8 1MHz测量时间?
目前,我有Atmega8 1MHz微控制器。我正在使用C语言。 因此,基本上我的程序显示了7个段显示器上的数字。 而且,每次按下按钮时,它会
立即增加数字+1,我想测量时间,如果用户按下按钮3秒钟。我唯一需要的是如何测量中断到3秒钟。 我需要背后的逻辑,我应该使用if语句吗?否则我不知道
这里是我的代码:
#define F_CPU 1000000UL
#define IRQ1 INT0_vect
#define IRQ2 INT1_vect
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
volatile int the_count = 0;
volatile int i;
volatile int k;
ISR(IRQ1){
if (the_count < 100){
the_count++;
i = the_count % 10;
k = the_count / 10;
}
else{
the_count = 0;
i = the_count % 10;
k = the_count / 10;
}
}
ISR(IRQ2){
if (the_count < 100){
the_count = the_count;
i = the_count % 10;
k = the_count / 10;
}
else{
the_count = 0;
i = the_count % 10;
k = the_count / 10;
}
}
void init()
{
DDRD = 0b00000111;
DDRB = 0b11111111;
PORTB = 255;
_delay_ms(2000);
PORTB = 0;
GICR = 0xc0;
MCUCR = 0x08;
IRQ1;
IRQ2;
}
int main(void){
init();
GICR = 0xc0;
MCUCR = 0x08;
sei();
int digit[] = {0b000000101, 0b10111101, 0b00100110, 0b10100100, 0b10011100, 0b11000100, 0b01000100, 0b10101101, 0b00000100, 0b10001100};
int dig1 = 0b00000110; //first digit area on display
int dig2 = 0b00000101; //second digit area on display
while (1)
{
if (k < 1){
PORTB = digit[0];
PORTD = dig1;
_delay_ms(1);
PORTD = dig2;
PORTB = digit[i];
_delay_ms(1);
}
else if (k>=1 && i==0 && the_count<100){
PORTB = digit[k];
PORTD = dig1;
_delay_ms(1);
PORTD = dig2;
PORTB = digit[0];
_delay_ms(1);
}
else if (k>=1 && i!=0 && the_count<100){
PORTB = digit[k];
PORTD = dig1;
_delay_ms(1);
PORTD = dig2;
PORTB = digit[i];
_delay_ms(1);
}
else {
the_count = 0;
}
}
}
Currently I have Atmega8 1MHz Microcontroller. I'm working with C language.
So basically my program shows numbers on the 7 segment display.
And each time you press the button it increases number +1
Right now I want to measure time and if user presses button for 3 seconds. Only thing I need is how to measure if interrupt reached to 3 seconds.
I need logic behind it, should I use if statement with delay? or I don't know maybe something else
Here is my code:
#define F_CPU 1000000UL
#define IRQ1 INT0_vect
#define IRQ2 INT1_vect
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
volatile int the_count = 0;
volatile int i;
volatile int k;
ISR(IRQ1){
if (the_count < 100){
the_count++;
i = the_count % 10;
k = the_count / 10;
}
else{
the_count = 0;
i = the_count % 10;
k = the_count / 10;
}
}
ISR(IRQ2){
if (the_count < 100){
the_count = the_count;
i = the_count % 10;
k = the_count / 10;
}
else{
the_count = 0;
i = the_count % 10;
k = the_count / 10;
}
}
void init()
{
DDRD = 0b00000111;
DDRB = 0b11111111;
PORTB = 255;
_delay_ms(2000);
PORTB = 0;
GICR = 0xc0;
MCUCR = 0x08;
IRQ1;
IRQ2;
}
int main(void){
init();
GICR = 0xc0;
MCUCR = 0x08;
sei();
int digit[] = {0b000000101, 0b10111101, 0b00100110, 0b10100100, 0b10011100, 0b11000100, 0b01000100, 0b10101101, 0b00000100, 0b10001100};
int dig1 = 0b00000110; //first digit area on display
int dig2 = 0b00000101; //second digit area on display
while (1)
{
if (k < 1){
PORTB = digit[0];
PORTD = dig1;
_delay_ms(1);
PORTD = dig2;
PORTB = digit[i];
_delay_ms(1);
}
else if (k>=1 && i==0 && the_count<100){
PORTB = digit[k];
PORTD = dig1;
_delay_ms(1);
PORTD = dig2;
PORTB = digit[0];
_delay_ms(1);
}
else if (k>=1 && i!=0 && the_count<100){
PORTB = digit[k];
PORTD = dig1;
_delay_ms(1);
PORTD = dig2;
PORTB = digit[i];
_delay_ms(1);
}
else {
the_count = 0;
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我不会涉足所有这些代码来回答您的问题 - 尤其是因为您的命名约定,缺乏评论或I/O抽象使得很难确定I/O对于什么或代码做什么。但是“逻辑”将如下(替换时间和I / O呼叫与您可用的电话或可根据您适当实施的电话):
然后,您将具有表单的投票循环:
零 - 列表 /无忙碌的等待投票使您可以在循环中执行其他工作。当然,其他工作也应避免延迟和繁忙的等待 - 您的循环时间(因此按钮轮询率)是循环中完成的所有工作(包括延迟)的总和,因此对于最响应的系统,您需要最大程度地减少完成的工作,并尽可能确定循环(恒定循环时间)。
具体来说:
您不需要使用中断(另一个也许是时间安排的刻度中断)。您可以,并且中断可能只是设置一个由
isbuttonpresse()
返回的标志,但它仅添加了复杂性(尤其是WRT Switch de-Bounce),我建议简单地将其进行轮询,您不应使用延迟 - 在延迟期间,您无需做其他有用的工作。
(除非您使用的是多线程调度程序)。改用时间戳和经过时间,避免任何形式的“繁忙等待”。
您确实需要考虑开关反弹,这可以类似地处理:
进一步:如果循环中完成的工作很小,但是您需要一个特定而确定性的循环时间,该时间比身体执行时间更长(例如,这是必不可少的然后,在PID控件循环中:
我很长一段时间没有使用AVR,但是如果您还没有合适的计时函数,则
getTickMillisec()
(以及初始化和ISR)可以以以下方式实现:请注意
getTickMillisec()
- 访问tick_millisec
在8位设备上是非原子一部分通过它被阅读。循环将其重新读取直到一致(即相同的值读了两次)。另外,您可以简单地禁用中断:但这可能会影响中断处理程序的时机,因此最好避免。
有关16位timer1的详细信息,请参见 atmega8数据表来自第75页。
I am not about to wade through all that code to answer your question - not least because your naming convention, lack of comments or I/O abstraction make it very difficult to determine what I/O is for what or what code does what. But the "logic" would be as follows (replace timing and I/O calls with those available to, or implemented by you as appropriate):
Then you would have a polling loop of the form:
The zero-delay / no busy-wait polling allows you to perform other work in the loop. Of course the other work should also avoid delays and busy-waits - your loop-time (and therefore the button polling rate) is the sum of all the work done in the loop (including delays) so for the most responsive system you need to minimise the work done and make the loop as deterministic (constant loop time) as possible.
Specifically:
you do not need to use interrupts (other then a tick interrupt for timing perhaps). You could, and the interrupt might simply set a flag that is returned by
isButtonPressed()
for example, but it only adds complexity (especially w.r.t. switch de-bounce), and I would advise simply polling it,you should not use a delay - during a delay you can do no other useful work.
(unless you are using a multi-thread scheduler). Use timestamping and elapsed time instead, and avoid "busy-waits" of any kind.
You do need to consider switch bounce, and that can be handles similarly:
Further if the work done in the loop is minimal, but you want a specific and deterministic loop time that is longer then the body execution time (that would be essential for example in a PID control loop), then:
I have not used an AVR in a long time, but if you do not already have a suitable timing function the
getTickMillisec()
(along with initialisation and ISR) can be implemented in the following manner:Note the loop in
getTickMillisec()
- access totick_millisec
is non-atomic on an 8 bit device, so it is possible that the ISR updates part way through it being read. The loop re-reads it until it is consistent (i.e. the same value read twice). Alternatively you could simply disable interrupts:But that can affect the timing of interrupt handlers in general so might be best avoided.
For details of the 16 bit TIMER1 see the ATmega8 datasheet from page 75.