Question about Bluepill arduino using OnePulse mode

Post here first, or if you can't find a relevant section!
ozcar
Posts: 143
Joined: Wed Apr 29, 2020 9:07 pm
Answers: 5

Re: Question about Bluepill arduino using OnePulse mode

Post by ozcar »

It sounds like you are getting close.

I'm pretty sure that if I wanted to, I could create a program that behaves that way, where deleting "unused" variables could make it work or not. How you have managed to do that accidentally is impossible to say when you show us only tiny parts of your code. Now if you are having a problem with some little part of a big project, then creating a small self-contained example that demonstrated the problem would be Good Thing, but what you posted does not demonstrate anything.

Taking a step back to what you said before.
xlwww wrote: Tue Dec 27, 2022 1:24 pm I am using Timer2 channel1 (PA0) to drive the DHT11 sensor, saving CPU resources for computationally intensive work.
The specifications for the DHT11 says you can read it at most once per second. Including the 18ms start pulse, it takes a maximum of 23ms to get a reading. Than means that whatever you do, you stand to gain an extra 2.3% of total available CPU time for your computations. If that is enough to make or break your project, perhaps you should consider using a faster processor. I quite like the STM32F411 Blackpill boards.

Do you have some good reason to not use the official STM core?
xlwww
Posts: 14
Joined: Tue Dec 27, 2022 9:19 am

Re: Question about Bluepill arduino using OnePulse mode

Post by xlwww »

Happy New Year! Here is my code, I tested it for days and it doesn't work. Since it only responds once the first time, I use print_reg() to record the main register state before it works fine, and try to restore the first time register state on the next time. At the same time, when an interrupt is triggered, trigger the status of another pin for monitoring, but it doesn't work, too bad. In this example it doesn't seem to work properly due to variable increment. The complete project seems to be running normally due to an unknown bug, which is metaphysical. can you please take a look.Thanks~.

Code: Select all

int32_t channel_1_start=0, channel_1_stop=0, channel_1=0;
int32_t DHT11=PA0;
int32_t DHT11_data[50]={0},index1=0;

void setup() {
   Serial2.begin(115200);
   Serial2.println(F("DHTxx test!"));
   pinMode(PB11, OUTPUT);
   print_reg();
}

void loop() {
  // put your main code here, to run repeatedly:
    TIMER2_BASE->CCER=0;
    Timer2.detachInterrupt(TIMER_CH1);
    TIMER2_BASE->CCMR1 &=0x0000;
    TIMER2_BASE->CCER &= ~TIMER_CCER_CC1P; 

    Request() ;  /* send start pulse */
    delay(200);
    if(index1==41)
    {
      Serial2.println("OK");
    }
    else
    {
      Serial2.println("error");
    }
    for(int i=0;i<50;i++)
      DHT11_data[i]=0;
    delay(2000);
    index1=0;
}


void Request()      /* Microcontroller send request */
{
  pinMode(DHT11, OUTPUT);
  print_reg();
  digitalWrite(DHT11,LOW); 
  uint16_t PulseLOW = 25000; // should > 18ms
  uint16_t PulseHIGH = 30; // not important
 // pinMode(DHT11, PWM);

  Timer2.detachInterrupt(TIMER_CH1);
  Timer2.pause(); // stop the timers before configuring them

//  Serial2.println(TIMER2_BASE->CCMR1==);

//TIMER2_BASE->CCMR1 = 0x6868;
  Timer2.setChannel1Mode(TIMER_OUTPUT_COMPARE);
 // timer_oc_set_mode(TIMER2, 1, TIMER_OC_MODE_PWM_2, TIMER_OC_PE);//set PWM Mode2,and enable
  Timer2.setPrescaleFactor(72); // 1 microsecond resolution
  Timer2.setOverflow(PulseLOW + PulseHIGH-1);
  Timer2.setCompare(TIMER_CH1, PulseLOW);
 // Triggered after PulseLOW
  Timer2.attachInterrupt(TIMER_CH1,Response);  
  // counter setup in one pulse mode
  //TIMER2_BASE->CR1 = TIMER_CR1_CEN;
 // TIMER2_BASE->CR1 = ( TIMER_CR1_OPM ); // one pulse mode
 // TIMER2_BASE->CCER&= ~TIMER_CCER_CC1P ; // enable channels 1 

//Timer2.attachInterrupt(TIMER_CH1,Response);


  Timer2.refresh(); // start timer 2
  Timer2.resume(); // let timer 2 run


  
/*
                    Using PWM Mode 2

  _______20MS__________-------------------18MS-------------------___________
  ^                    ^                                         ^
  |<----PulseLOW------>|<-- PulseHIGH, but don't need attention->|      
                       ^
                       |
                       
              Compare1Interrupt
              execution Response(),
           Change the mode of the Timer2

 */

}
 

void Response()
{


    digitalWrite(DHT11,HIGH); 
    pinMode(DHT11, INPUT_PULLUP);
    Serial2.println(1);
    Timer2.attachInterrupt(TIMER_CH1,handler_channel_1);
    TIMER2_BASE->CCR1=0;
      TIMER2_BASE->CR1 = TIMER_CR1_CEN;
      TIMER2_BASE->CR2 = 0;
      TIMER2_BASE->SMCR = 0;
      TIMER2_BASE->DIER = TIMER_DIER_CC1IE ;
      TIMER2_BASE->EGR = 0;
      TIMER2_BASE->CCMR1 = 0b100000001; //Register is set like this due to a bug in the define table (30-09-2017)
      TIMER2_BASE->CCMR2 = 0;
      TIMER2_BASE->CCER = TIMER_CCER_CC1E ;
      TIMER2_BASE->PSC = 71;
      TIMER2_BASE->ARR = 0xFFFF;
      TIMER2_BASE->DCR = 0;
   //     Timer2.refresh(); // start timer 2
//  Timer2.resume(); // let timer 2 run
  
}
void print_reg()
{
      Serial2.println("TIMER2_BASE->CR1 ="+ (String)TIMER2_BASE->CR1+';');
      Serial2.println("TIMER2_BASE->CR2 =" +(String)TIMER2_BASE->CR2+';');
      Serial2.println("TIMER2_BASE->SMCR ="+ (String)TIMER2_BASE->SMCR+';');
      Serial2.println("TIMER2_BASE->DIER ="+ (String)TIMER2_BASE->DIER+';') ;
      Serial2.println("TIMER2_BASE->EGR = "+(String)TIMER2_BASE->EGR+';');
      Serial2.println("TIMER2_BASE->CCMR1 = "+(String)TIMER2_BASE->CCMR1+';');
      Serial2.println("TIMER2_BASE->CCMR2 = "+(String)TIMER2_BASE->CCMR2+';');
      Serial2.println("TIMER2_BASE->CCER = "+(String)TIMER2_BASE->CCER+';') ;
      Serial2.println("TIMER2_BASE->PSC = "+(String)TIMER2_BASE->PSC+';');
      Serial2.println("TIMER2_BASE->ARR = "+(String)TIMER2_BASE->ARR+';');
      Serial2.println("TIMER2_BASE->DCR = "+(String)TIMER2_BASE->DCR+';');
      Serial2.println();
}
void handler_channel_1(void) {                           //This function is called when channel 1 is captured.
    if (0b1 & GPIOA_BASE->IDR  >> 0) {                     //If the receiver channel 1 input pulse on A0 is high.
      channel_1_start = TIMER2_BASE->CCR1;                 //Record the start time of the pulse.
      TIMER2_BASE->CCER |= TIMER_CCER_CC1P;                //Change the input capture mode to the falling edge of the pulse.
      digitalWrite(PB11, HIGH);
    }
    else {                                                 //If the receiver channel 1 input pulse on A0 is low.
      channel_1 = TIMER2_BASE->CCR1 - channel_1_start;     //Calculate the total pulse time.
      if (channel_1 < 0)channel_1 += 0xFFFF;               //If the timer has rolled over a correction is needed.
      TIMER2_BASE->CCER &= ~TIMER_CCER_CC1P;               //Change the input capture mode to the rising edge of the pulse.
      DHT11_data[index1++]=channel_1;
      digitalWrite(PB11, LOW);
  //    Serial2.println(index1);
    }
}
Last edited by xlwww on Sun Jan 01, 2023 3:20 pm, edited 9 times in total.
xlwww
Posts: 14
Joined: Tue Dec 27, 2022 9:19 am

Re: Question about Bluepill arduino using OnePulse mode

Post by xlwww »

ozcar wrote: Sat Dec 31, 2022 3:05 am It sounds like you are getting close.

I'm pretty sure that if I wanted to, I could create a program that behaves that way, where deleting "unused" variables could make it work or not. How you have managed to do that accidentally is impossible to say when you show us only tiny parts of your code. Now if you are having a problem with some little part of a big project, then creating a small self-contained example that demonstrated the problem would be Good Thing, but what you posted does not demonstrate anything.

Taking a step back to what you said before.
xlwww wrote: Tue Dec 27, 2022 1:24 pm I am using Timer2 channel1 (PA0) to drive the DHT11 sensor, saving CPU resources for computationally intensive work.
The specifications for the DHT11 says you can read it at most once per second. Including the 18ms start pulse, it takes a maximum of 23ms to get a reading. Than means that whatever you do, you stand to gain an extra 2.3% of total available CPU time for your computations. If that is enough to make or break your project, perhaps you should consider using a faster processor. I quite like the STM32F411 Blackpill boards.

Do you have some good reason to not use the official STM core?
Because the library I want to import only runs on Bluepill, not suitable for F4, and I only have Bluepill now, which is embarrassing. :( :( :( :(,And the execution efficiency of the official library does not seem to be as efficient as Roger's Core.
dannyf
Posts: 447
Joined: Sat Jul 04, 2020 7:46 pm

Re: Question about Bluepill arduino using OnePulse mode

Post by dannyf »

your approach (and implementation) is driven by your goal and your constraints.

the code you are using is a blocking implementation and your goal seems to be a non-blocking implementation.

the most "correct" implementation would be to use interrupts - a state machine implementation.

If you are willing to put up with a short "blocking", and to re-use the code, you can use the state machine for the mcu to send the low pulse, and use blocking implementation for the response and data reads.

something like this would work:

Code: Select all

//dht state machine
  state = idle:
    if (idle time > 1 sec) state = ready; //can now process the start signal
  state = ready:
    if (pin = now) {time=millis(); state = starting_low;} //starting low signal received
  state = starting_low:
    if (millis() - time > 18 ms && pin = high) {time=millis(); state = starting_high;} //starting high signal received
  state = starting_high:
    if (millis() - time > xx us) state = response; //response signal
  state = response:
    change the pin to output; and send the response signal;
    state = request;
  state = request:
    read the data;
    state = data_available;
  ...
essentially it goes through the different states based on the pin status and timing.
xlwww
Posts: 14
Joined: Tue Dec 27, 2022 9:19 am

Re: Question about Bluepill arduino using OnePulse mode

Post by xlwww »

dannyf wrote: Sun Jan 01, 2023 6:36 pm your approach (and implementation) is driven by your goal and your constraints.

the code you are using is a blocking implementation and your goal seems to be a non-blocking implementation.

the most "correct" implementation would be to use interrupts - a state machine implementation.

If you are willing to put up with a short "blocking", and to re-use the code, you can use the state machine for the mcu to send the low pulse, and use blocking implementation for the response and data reads.

something like this would work:

Code: Select all

//dht state machine
  state = idle:
    if (idle time > 1 sec) state = ready; //can now process the start signal
  state = ready:
    if (pin = now) {time=millis(); state = starting_low;} //starting low signal received
  state = starting_low:
    if (millis() - time > 18 ms && pin = high) {time=millis(); state = starting_high;} //starting high signal received
  state = starting_high:
    if (millis() - time > xx us) state = response; //response signal
  state = response:
    change the pin to output; and send the response signal;
    state = request;
  state = request:
    read the data;
    state = data_available;
  ...
essentially it goes through the different states based on the pin status and timing.
Thank you for your suggestion. In fact, in the complete project, it will not be blocked. The above code is an independent DHT11 driver using timer. I use the VGA library in my complete project, and the screen will be refreshed. During this time, there is enough Time to replace delay(), and I don't want to use the function of mills(),my intention is to use the timer to complete the drive.
ozcar
Posts: 143
Joined: Wed Apr 29, 2020 9:07 pm
Answers: 5

Re: Question about Bluepill arduino using OnePulse mode

Post by ozcar »

So I took your code and tried it. Yes, I had to install the "Roger" core to get it to compile. It has been a very long time since I used this core and I have either forgotten, or perhaps I never did know where Serial2 goes to, so all I did initially was to redefine Serial2 as Serial so I could see the output.

Duly loaded into a Bluepill board, and it repeatedly printed the timer registers and "error". Now given there was no DHT11 attached, that is no big surprise. I don't have a DHT11, but not easily defeated, I programmed another Bluepill to act the part of a DHT11 (just sending bogus constant humidity and temperature values). For good measure I put an external 5.6K pullup resistor to 3.3V.

Now your code seems perfectly happy to say things are OK:

Code: Select all

15:15:57.280 -> TIMER2_BASE->CR1 =1;
15:15:57.280 -> TIMER2_BASE->CR2 =0;
15:15:57.280 -> TIMER2_BASE->SMCR =0;
15:15:57.280 -> TIMER2_BASE->DIER =0;
15:15:57.280 -> TIMER2_BASE->EGR = 0;
15:15:57.280 -> TIMER2_BASE->CCMR1 = 0;
15:15:57.280 -> TIMER2_BASE->CCMR2 = 0;
15:15:57.280 -> TIMER2_BASE->CCER = 0;
15:15:57.280 -> TIMER2_BASE->PSC = 71;
15:15:57.280 -> TIMER2_BASE->ARR = 65535;
15:15:57.280 -> TIMER2_BASE->DCR = 0;
15:15:57.280 -> 
15:15:57.280 -> 1
15:15:57.467 -> OK
15:15:59.457 -> TIMER2_BASE->CR1 =1;
15:15:59.457 -> TIMER2_BASE->CR2 =0;
15:15:59.457 -> TIMER2_BASE->SMCR =0;
15:15:59.457 -> TIMER2_BASE->DIER =0;
15:15:59.457 -> TIMER2_BASE->EGR = 0;
15:15:59.457 -> TIMER2_BASE->CCMR1 = 0;
15:15:59.457 -> TIMER2_BASE->CCMR2 = 0;
15:15:59.457 -> TIMER2_BASE->CCER = 0;
15:15:59.457 -> TIMER2_BASE->PSC = 71;
15:15:59.457 -> TIMER2_BASE->ARR = 65535;
15:15:59.457 -> TIMER2_BASE->DCR = 0;
15:15:59.457 -> 
15:15:59.503 -> 1
15:15:59.691 -> OK
... 
That repeats for as long as I let it.

So, I then inserted code to print the DHT11_data array just before it says "OK":

Code: Select all

15:34:23.885 -> 82
15:34:23.885 -> 26
15:34:23.885 -> 27
15:34:23.885 -> 27
15:34:23.885 -> 27
15:34:23.885 -> 27
15:34:23.885 -> 27
15:34:23.885 -> 27
15:34:23.885 -> 71
15:34:23.885 -> 71
15:34:23.885 -> 71
15:34:23.885 -> 71
15:34:23.885 -> 71
15:34:23.885 -> 27
15:34:23.885 -> 71
15:34:23.885 -> 27
15:34:23.885 -> 27
15:34:23.885 -> 27
15:34:23.885 -> 27
15:34:23.885 -> 27
15:34:23.885 -> 27
15:34:23.885 -> 26
15:34:23.932 -> 26
15:34:23.932 -> 70
15:34:23.932 -> 71
15:34:23.932 -> 71
15:34:23.932 -> 71
15:34:23.932 -> 71
15:34:23.932 -> 27
15:34:23.932 -> 26
15:34:23.932 -> 70
15:34:23.932 -> 70
15:34:23.932 -> 71
15:34:23.932 -> 71
15:34:23.932 -> 71
15:34:23.932 -> 26
15:34:23.932 -> 70
15:34:23.932 -> 70
15:34:23.932 -> 70
15:34:23.932 -> 71
15:34:23.932 -> 71
15:34:23.932 -> 0
15:34:23.932 -> 0
15:34:23.932 -> 0
15:34:23.932 -> 0
15:34:23.932 -> 0
15:34:23.932 -> 0
15:34:23.932 -> 0
15:34:23.932 -> 0
15:34:23.932 -> 0
15:34:23.932 -> OK
It is also happy to continue doing that for as long as I like. The time values printed might vary +/- 1, but you would have absolutely no problem translating those into the bit values.

So, where is the problem? Well, here are some comments & suggestions:

DHT11_data and index1 should be declared as volatile because they are updated in one of the interrupt routines.

It is not a good idea to print things within interrupt routines.

You seem to have "gotten away" with those two, but more of a problem is the fact that you do not check the array index in the handler_channel_1() ISR. If the sensor misbehaves, or if you get some random noise pulses on the sensor line, you can blindly plough on and destroy whatever happens to be in RAM beyond the array. That is a very good way to cause the sort of problem you reported earlier, where adding some "unused" variables might magically mask the problem. At the very least, you should not touch the array if the index gets too large, but actually, you might as well stop the timer as soon as you have all the data.

I would also suggest that in the Response() ISR, you should stop the timer counter (turn off CEN flag in CR1) before changing all the other registers, and then start the counter as the last thing there. While you are about it, you could set timer counter to zero there too, then you could perhaps generate an interrupt if the response takes too long, if something grinds to a halt part-way through a transmission (ARR value of around 5000???).

Another possibility, and maybe you were going to do that anyway, would be to put the yet-to-be-written code that translates the time values to data bits into the ISR. That would reduce the RAM usage considerably. Remember you only have 20k and it can get used up very easily.

What is the library that you were going to use?
xlwww
Posts: 14
Joined: Tue Dec 27, 2022 9:19 am

Re: Question about Bluepill arduino using OnePulse mode

Post by xlwww »

ozcar wrote: Mon Jan 02, 2023 6:06 am So I took your code and tried it. Yes, I had to install the "Roger" core to get it to compile. It has been a very long time since I used this core and I have either forgotten, or perhaps I never did know where Serial2 goes to, so all I did initially was to redefine Serial2 as Serial so I could see the output.

Duly loaded into a Bluepill board, and it repeatedly printed the timer registers and "error". Now given there was no DHT11 attached, that is no big surprise. I don't have a DHT11, but not easily defeated, I programmed another Bluepill to act the part of a DHT11 (just sending bogus constant humidity and temperature values). For good measure I put an external 5.6K pullup resistor to 3.3V.

Now your code seems perfectly happy to say things are OK:

Code: Select all

15:15:57.280 -> TIMER2_BASE->CR1 =1;
15:15:57.280 -> TIMER2_BASE->CR2 =0;
15:15:57.280 -> TIMER2_BASE->SMCR =0;
15:15:57.280 -> TIMER2_BASE->DIER =0;
15:15:57.280 -> TIMER2_BASE->EGR = 0;
15:15:57.280 -> TIMER2_BASE->CCMR1 = 0;
15:15:57.280 -> TIMER2_BASE->CCMR2 = 0;
15:15:57.280 -> TIMER2_BASE->CCER = 0;
15:15:57.280 -> TIMER2_BASE->PSC = 71;
15:15:57.280 -> TIMER2_BASE->ARR = 65535;
15:15:57.280 -> TIMER2_BASE->DCR = 0;
15:15:57.280 -> 
15:15:57.280 -> 1
15:15:57.467 -> OK
15:15:59.457 -> TIMER2_BASE->CR1 =1;
15:15:59.457 -> TIMER2_BASE->CR2 =0;
15:15:59.457 -> TIMER2_BASE->SMCR =0;
15:15:59.457 -> TIMER2_BASE->DIER =0;
15:15:59.457 -> TIMER2_BASE->EGR = 0;
15:15:59.457 -> TIMER2_BASE->CCMR1 = 0;
15:15:59.457 -> TIMER2_BASE->CCMR2 = 0;
15:15:59.457 -> TIMER2_BASE->CCER = 0;
15:15:59.457 -> TIMER2_BASE->PSC = 71;
15:15:59.457 -> TIMER2_BASE->ARR = 65535;
15:15:59.457 -> TIMER2_BASE->DCR = 0;
15:15:59.457 -> 
15:15:59.503 -> 1
15:15:59.691 -> OK
... 
That repeats for as long as I let it.

So, I then inserted code to print the DHT11_data array just before it says "OK":

Code: Select all

15:34:23.885 -> 82
15:34:23.885 -> 26
15:34:23.885 -> 27
15:34:23.885 -> 27
15:34:23.885 -> 27
15:34:23.885 -> 27
15:34:23.885 -> 27
15:34:23.885 -> 27
15:34:23.885 -> 71
15:34:23.885 -> 71
15:34:23.885 -> 71
15:34:23.885 -> 71
15:34:23.885 -> 71
15:34:23.885 -> 27
15:34:23.885 -> 71
15:34:23.885 -> 27
15:34:23.885 -> 27
15:34:23.885 -> 27
15:34:23.885 -> 27
15:34:23.885 -> 27
15:34:23.885 -> 27
15:34:23.885 -> 26
15:34:23.932 -> 26
15:34:23.932 -> 70
15:34:23.932 -> 71
15:34:23.932 -> 71
15:34:23.932 -> 71
15:34:23.932 -> 71
15:34:23.932 -> 27
15:34:23.932 -> 26
15:34:23.932 -> 70
15:34:23.932 -> 70
15:34:23.932 -> 71
15:34:23.932 -> 71
15:34:23.932 -> 71
15:34:23.932 -> 26
15:34:23.932 -> 70
15:34:23.932 -> 70
15:34:23.932 -> 70
15:34:23.932 -> 71
15:34:23.932 -> 71
15:34:23.932 -> 0
15:34:23.932 -> 0
15:34:23.932 -> 0
15:34:23.932 -> 0
15:34:23.932 -> 0
15:34:23.932 -> 0
15:34:23.932 -> 0
15:34:23.932 -> 0
15:34:23.932 -> 0
15:34:23.932 -> OK
It is also happy to continue doing that for as long as I like. The time values printed might vary +/- 1, but you would have absolutely no problem translating those into the bit values.

So, where is the problem? Well, here are some comments & suggestions:

DHT11_data and index1 should be declared as volatile because they are updated in one of the interrupt routines.

It is not a good idea to print things within interrupt routines.

You seem to have "gotten away" with those two, but more of a problem is the fact that you do not check the array index in the handler_channel_1() ISR. If the sensor misbehaves, or if you get some random noise pulses on the sensor line, you can blindly plough on and destroy whatever happens to be in RAM beyond the array. That is a very good way to cause the sort of problem you reported earlier, where adding some "unused" variables might magically mask the problem. At the very least, you should not touch the array if the index gets too large, but actually, you might as well stop the timer as soon as you have all the data.

I would also suggest that in the Response() ISR, you should stop the timer counter (turn off CEN flag in CR1) before changing all the other registers, and then start the counter as the last thing there. While you are about it, you could set timer counter to zero there too, then you could perhaps generate an interrupt if the response takes too long, if something grinds to a halt part-way through a transmission (ARR value of around 5000???).

Another possibility, and maybe you were going to do that anyway, would be to put the yet-to-be-written code that translates the time values to data bits into the ISR. That would reduce the RAM usage considerably. Remember you only have 20k and it can get used up very easily.

What is the library that you were going to use?
Serial port 2 is on PA2, PA3.If you didn't change my code then, it won't work after connecting DHT11, I have many DHT11 sensors, tried many times. Maybe using another MCU to simulate DHT11 will have a different effect. I drew my own PCB, it should not have external influences.
Last edited by xlwww on Mon Jan 02, 2023 9:51 am, edited 1 time in total.
xlwww
Posts: 14
Joined: Tue Dec 27, 2022 9:19 am

Re: Question about Bluepill arduino using OnePulse mode

Post by xlwww »

I found the reason again, I defined an array char temp[10]="", hum[10]=""; it seems to be out of bounds when using sprintf, I changed them to char temp[30]= "",hum[30]=""; it can work! It turns out that the array should be set as large as possible when starting to debug.Thank you for your suggestion~ :lol: :lol: :lol:
ozcar
Posts: 143
Joined: Wed Apr 29, 2020 9:07 pm
Answers: 5

Re: Question about Bluepill arduino using OnePulse mode

Post by ozcar »

I can easily get your previous code to fail - as in stop responding altogether, by just presenting it with more pulses than it expects.

I cannot get it to stop responding if I add this to the handler_channel_1() routine:

Code: Select all

void handler_channel_1(void) {                           //This function is called when channel 1 is captured.
      if ( index1 > 49 ) return;                         // prevent overrun of data array
      if (0b1 & GPIOA_BASE->IDR  >> 0) {                 //If the receiver channel 1 input pulse on A0 is high.
      ... 
I'm not sure exactly what you have done now, but adding stray arrays is not the answer. If you do that, don't be surprised if it starts to fail again as soon as you add something else to it.

I can see that at some time you tried to print the index1 value in the interrupt routine, but that statement has been commented out. So, maybe you found out for yourself that using Serialx.print() is not such a good idea in an interrupt routine, but it seems that you were somehow suspicious of index1.

If you really want to work out what is happening, change the interrupt routine so that it does not just bail out completely when the index gets too great. Instead, when the index is greater than the array size, stop storing the values into the array, but still increment index1. Then print out index1 in loop(). I'll bet you will find that without that change you were running beyond the end of the array (in other words, you will sometimes see values of index1 > 49).
ag123
Posts: 1655
Joined: Thu Dec 19, 2019 5:30 am
Answers: 24

Re: Question about Bluepill arduino using OnePulse mode

Post by ag123 »

for DHT11, DHT22
https://www.sparkfun.com/datasheets/Sen ... /DHT22.pdf
https://cdn-shop.adafruit.com/datasheet ... hinese.pdf

I adopted codes from Adafruit's library, which did not use a 'OnePulse' mode
https://github.com/adafruit/DHT-sensor-library

the thread about DHT11, DHT22 is here
viewtopic.php?t=530
in addition, to that in the above thread I even managed to use the internal pull up in the stm32 gpio and I literally saved a pull up resistor and is able to directly connect stm32 to the DHT11, DHT22 directly simply using (dupont) wires, no addition pull up resistor etc is needed.

my codes is in this thread
viewtopic.php?p=3517#p3517
the codes is based on Adafruit's implementation, I did use a timer and the *secret* / trick is this little piece of code, in the expectPulse implementation

Code: Select all

uint16_t expectPulse(uint8_t val) {
	//start the counter
	Timer1.refresh();
	timeout = false;
	Timer1.resume();
	while(digitalRead(dht_data_pin) == val && !timeout);
	Timer1.pause();
	return Timer1.getCount();
}

void timer_handler() {
	timeout = true;
	Timer1.pause();
}
The main thing about DHT11, DHT22 is measuring the time interval for '0' (zero) and '1' (one)
DHT11 signals
DHT11 signals
dht11a.png (93.76 KiB) Viewed 880 times
Hence, i adopted a timer to do the job, the timer is controlled directly from codes, timer->refresh() reset the counter.
timer1->resume() start the timer
then that

Code: Select all

while(digitalRead(dht_data_pin) == val && !timeout);
simply goes in a wait loop (spin lock) until the value changes.
once the value changes, stop the timer timer->pause()
and timer->getcount() is the count of the timer.
So expectPulse(value) basically measures and return the interval in that particular state i.e. value = 0 or value = 1.

In this way you can easily use a timer to measure durations, and that STM32 is so fast that I hardly have any misclassified duration for the '0' and '1' intervals for all the while that I'm using it. It is normally accurate to a single tick (1 us) on the timer count, even with all that code control of the timer, refresh(), resume() and pause(). I did not use any 'esoteric' 'One Pulse' mode.

i think it may be possible to use STM32's input capture mode to do these timing measurements, but that I did not attempt that as I find Adafruit's implementation simplier to adopt and implement. This is possible as the DHT11 / DHT22 signals are after all quite slow and that it is possible to time the '0' and '1' intervals simply doing all that in code rather than hardware. The only 'hardware' used is that timer, and mainly to keep count for the duration.

This code probably won't work in an RTOS vTask() as a single context switch 1 ms can throw all that measurements totally off track, but it works ok in 'single threaded' *duinoish setup. I'm guessing other 'hardware' approaches, could be to (ab)use SPI or UART to similarly do these 'measurements'
Post Reply

Return to “General discussion”