Timer Arduino P10显示和时间计数

Timer Arduino P10显示和时间计数,timer,arduino,dot-matrix,Timer,Arduino,Dot Matrix,各位,我正在使用,P10点阵显示和Arduino Uno。我正在从这个链接使用P10库。我需要在显示模块上显示一小时倒计时。给定的库使用库。所以对于倒计时,我使用的是使用arduino定时器2的库 当我单独运行这两个库时,我在显示器上的滚动是完美的,我的计时器库也会产生一个纯1秒的中断。现在我所做的是在我的项目中添加库,我正在倒计时。但是现在我的MsTimer2突然不能产生纯1秒 这是代码 #include <MsTimer2.h> #include <TimerOne.h&g

各位,我正在使用,
P10点阵显示
Arduino Uno
。我正在从这个链接使用P10库。我需要在显示模块上显示一小时倒计时。给定的库使用库。所以对于倒计时,我使用的是使用arduino定时器2的库

当我单独运行这两个库时,我在显示器上的滚动是完美的,我的计时器库也会产生一个纯1秒的中断。现在我所做的是在我的项目中添加库,我正在倒计时。但是现在我的
MsTimer2
突然不能产生纯1秒

这是代码

#include <MsTimer2.h>
#include <TimerOne.h>
#include"SPI.h"
#include <ledP10.h>

LedP10 myled;
uint8_t minute = 0, second = 0, hour = 1;
volatile bool xIsCountDone = false;
volatile bool xIsInterruptOcuured = false;
char time_buff[100];

void setup() 
{
    Serial.begin(9600);
    myled.init(3,4,8,9 ,3);
    sprintf((char*)time_buff, "    %d%d:%d%d:%d%d", (hour/10), (hour%10),(minute/10), (minute%10),(second/10), (second%10));
    Serial.println((char*)time_buff);
    myled.showmsg_single_static((char*)time_buff, 0);
    xIsInterruptOcuured = false;
    //myled.showmsg_single_scroll("this is single led test",2,8,0);
    MsTimer2::set(1000, count);
    MsTimer2::start();
}

void loop() {
  if (xIsInterruptOcuured == true)
  {
    sprintf((char*)time_buff, "    %d%d:%d%d:%d%d", (hour/10), (hour%10),(minute/10), (minute%10),(second/10), (second%10));
    Serial.println((char*)time_buff);
    myled.showmsg_single_static((char*)time_buff, 0);
    xIsInterruptOcuured = false;
  }
}

void count(){
  second--;
  if (second <= 0 || second > 59)
  {
    second = 59;
    minute--;
    if (minute <= 0 || minute > 59)
    {
      minute = 59;
      hour--;
      if (hour <= 0 || hour > 12)
      {
        xIsCountDone =true;
      }
    }
  }
  Serial.println(millis());
  xIsInterruptOcuured = true;
}

在Arduino世界中,一些库正在禁用中断

所有WS2812 LED和您的LED都会出现这种情况。如果不禁用中断,外部设备将出现计时问题

所以,如果您使用另一个将禁用中断的库,则永远不要使用中断或带中断的库

您想使用P10库吗?可以,但不要在代码中使用中断。不要添加其他库,如IR_remote,因为它将无法正常工作

回到你的问题,只需更新循环中的计时器。不要等到一秒钟结束后才更新你的时间1秒钟!这将始终超过1秒

例如,您可以将毫秒转换为秒
seconds=millis()/1000。
您的循环可能是这样的:

void循环(){
currentSeconds=millis()/1000;//获取当前“时间”(实际上是程序启动后的毫秒数)
if(currentSeconds!=savedSeconds)//测试周期是否已过
{
savedSeconds=当前秒数;
Serial.println(millis());
第二--;
如果(第二个59){
秒=59;
分钟--;
若有(第59分钟){
分钟=59;
小时--;
若有(第12小时){
小时=0;
}
}
}
sprintf((char*)time_buff,“%d%d:%d%d:%d%d”,(小时/10),(小时%10),(分钟/10),(分钟%10),(秒/10),(秒%10));
myled.showmsg\u single\u static((char*)time\u buff,0);
}
}

此答案针对您的示例,使用
millis()
。通过不设置相对于当前时间的下一次更新,可以避免随着时间的推移累积错误。而是每次增加一秒。这样,主循环是否被中断阻塞了几毫秒并不重要

还请注意,您不必分别节省小时、分钟和秒,您只需计算它们:

unsigned long nextMillis = 1000;
unsigned long targetTime = 1 * 60 * 60 * 1000; // 1 hour in milliseconds

void setup(){
    myled.init(3,4,8,9,3);
    Serial.begin(9600);
    updateMyLed(0);
}


void updateMyLed( unsigned long elapsedTime ){

    char buffer[100];       
    unsigned long timeLeftInSeconds = (targetTime - elapsedTime) / 1000;

    uint8_t hour = timeLeftInSeconds / 3600;
    timeLeftInSeconds -= hour * 3600;
    uint8_t minute = timeLeftInSeconds / 60;
    uint8_t second = timeLeftInSeconds - (minute * 60);

    sprintf((char*)buffer, "    %d%d:%d%d:%d%d", (hour/10), (hour%10), (minute/10), (minute%10), (second/10), (second%10));
    myled.showmsg_single_static((char*)buffer, 0);
}

void loop() {

    if( millis() >= nextMillis ){
        updateMyLed(nextMillis);
        nextMillis += 1000;
    }

}

我没有时间深入研究你的密码。我懒惰的程序员的建议:买一个实时时钟,这样你就不必担心计时器中断:)更简单的解决方案是使用
millis()
函数,因为一小时倒计时不需要实时。@Fitzi使用millis()也不能给出准确的倒计时。12分钟左右有很大的差别。我用秒表测量。@Pigget是的,我有一个备用ds3231,但我想用计时器试试。但是如果什么都没有发生,那将是我唯一的选择。你能举个例子说明你是如何使用米利斯的吗?因为在一个小时的倒计时中休息12分钟很可能是其他问题的结果,这不是不准确的。谢谢你的回答。您使用的逻辑很好,我取消了对它的访问,但为了检查它是否给出了正确的时间,我只使用了Serial.println(millis())在循环中的if语句中,我发现有11.81秒的精确差异。此外,我对ledp10初始化进行了注释,并再次检查,它给出了精确的时间。现在我想我应该更改p10显示的库。所有的问题都发生在这个库中。p10库很可能在内部使用计时器,这会把事情搞砸。但是如果它真的把
millis()
函数也弄糟了,那么您应该更改它,是的。您熟悉我正在使用的显示模块的库吗?图书馆不干扰millis()的可能性有多大?我最好切换到ds3231从rtc获取时间。你有什么建议?谢谢你提供的信息。是的,我必须使用p10显示和库,但它可以是p10的任何库,而不是这个库,只要我可以滚动和显示字符串。说到代码,我完全不理解逻辑。您使用了
currentSeconds=millis()/1000然后您已选中currentSeconds!=节省的秒数。有很多次我保存的秒数将不等于当前秒数,大多数情况下,条件将为真,显示将更新多次是,抱歉。我更新了代码。您必须保存已保存的秒数。禁用中断的库的主要问题是,您的中断不会每次都执行。在脚本的循环中,您只需检查是否经过了1秒的时间以将时间减少1。但当1.2秒过去时,这也可能是真的。同样在我的例子中,一旦时间超过1秒,就会发生这种情况,但是使用这种方法不会损失任何毫秒。
unsigned long nextMillis = 1000;
unsigned long targetTime = 1 * 60 * 60 * 1000; // 1 hour in milliseconds

void setup(){
    myled.init(3,4,8,9,3);
    Serial.begin(9600);
    updateMyLed(0);
}


void updateMyLed( unsigned long elapsedTime ){

    char buffer[100];       
    unsigned long timeLeftInSeconds = (targetTime - elapsedTime) / 1000;

    uint8_t hour = timeLeftInSeconds / 3600;
    timeLeftInSeconds -= hour * 3600;
    uint8_t minute = timeLeftInSeconds / 60;
    uint8_t second = timeLeftInSeconds - (minute * 60);

    sprintf((char*)buffer, "    %d%d:%d%d:%d%d", (hour/10), (hour%10), (minute/10), (minute%10), (second/10), (second%10));
    myled.showmsg_single_static((char*)buffer, 0);
}

void loop() {

    if( millis() >= nextMillis ){
        updateMyLed(nextMillis);
        nextMillis += 1000;
    }

}