Arduino C++ Running two while loops at the same time - arduino-c++

I am trying to figure out how to run 2 while loops at the same time but in the easiest way possible?
I want one loop to check for a signal from the joystick that i connected to the Arduino.I want the second loop to display a face in the LCD screen and i want it to blink every 5 minutes.(I know it sounds weird)

The term you are looking for here is called multi-threading. The first thread will be for your joystick loop and the second will be fore your LCD screen. Depending on the board you are using, the strain added to the hardware will be different.
Regardless of board type, you can use a library such as protothreads to accomplish this. Here is the code from Digikey's tutorial on multithreading in arduino programs.
#include "protothreads.h"
#define LED_1 2
#define LED_2 3
pt ptSlowBlink;
pt ptFastBlink;
int fastBlinkThread(struct pt* pt)
{
PT_BEGIN(pt);
while(true)
{
digitalWrite(LED_1, HIGH);
PT_SLEEP(pt, 250);
digitalWrite(LED_1, LOW);
PT_SLEEP(pt, 250);
}
PT_END(pt);
}
int slowBlinkThread(struct pt* pt)
{
PT_BEGIN(pt);
while(true)
{
digitalWrite(LED_2, HIGH);
PT_SLEEP(pt, 1000);
digitalWrite(LED_2, LOW);
PT_SLEEP(pt, 1000);
}
PT_END(pt);
}
void setup()
{
PT_INIT(&ptSlowBlink);
PT_INIT(&ptFastBlink);
pinMode(LED_1, OUTPUT);
pinMode(LED_2, OUTPUT);
}
void loop()
{
PT_SCHEDULE(slowBlinkThread(&ptSlowBlink));
PT_SCHEDULE(fastBlinkThread(&ptFastBlink));
}
If the board you're using support Mbed OS, then there are also native features that will provide a significant increase in performance over the code above. It comes with some added learning curve but if you want to learn more the above tutorial also has a small introduction to Mbed OS multithreading.

Related

Raspberry Pi Pico locks up when I try to use interrupts

I'm trying to use encoders to track the movement of three wheels on a robot, but as soon as any of the motors move the robot "locks up", it stops responding to commands, stops printing to the serial monitor, and just keeps spinning its wheels until I turn it off. I cut out everything except just the code to track one encoder and tried turning the wheel by hand to sus out the problem, but it still locked up. And even more strangely, now it will start spinning one of the wheels even though I've removed any code that should have it do that, even by mistake.
I used the Arduino IDE to program the pico since I've got no familiarity with python, but I can't find any information or troubleshooting tips for using interrupts with the pico that don't assume you're using micropython.
Here's the simplified code I'm using to try to find the problem. All it's meant to do is keep track of how many steps the encoder has made and print that to the serial monitor every second. Ive tried removing the serial and having it light up LEDs instead but that didn't help.
int encA = 10;
int encB = 11;
int count = 0;
int timer = 0;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(encA),readEncoder,RISING);
timer = millis();
}
void loop() {
// put your main code here, to run repeatedly:
if (timer - millis() > 5000) {
Serial.println(count);
timer = millis();
}
}
void readEncoder() {
int bVal = digitalRead(encB);
if (bVal == 0) {
count--;
}
else{
count++;
}
}
Does the mapping function digitalPinToInterrupt for the Pi Pico work?
Can you try just using the interrupt number that corresponds to the pi?
attachInterrupt(9,readEncoder,RISING); //Or the number 0-25 which maps to that pin
https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware__irq.html
You have the wrong pin to encoder in your example (maybe you incorrectly copy and pasted)?
attachInterrupt(digitalPinToInterrupt(**encA**),readEncoder,RISING);
void readEncoder() {
int bVal = digitalRead(**encB**); ...}
There is similar code on GitHub that you could modify and try instead.
https://github.com/jumejume1/Arduino/blob/master/ROTARY_ENCODER/ROTARY_ENCODER.ino
It might help you find a solution.
Also,
https://www.arduino.cc/reference/en/libraries/rpi_pico_timerinterrupt/
The interrupt number corresponds to the pin (unless you have reassigned it or disabled it) so for pin 11 the code can be:
attachInterrupt(11, buttonPressed, RISING);
This works:
bool buttonPress = false;
unsigned long buttonTime = 0; // To prevent debounce
void setup() {
Serial.begin(9600);
pinMode(11, INPUT_PULLUP);
attachInterrupt(11, buttonPressed, RISING);
// can be CHANGE or LOW or RISING or FALLING or HIGH
}
void loop() {
if(buttonPress) {
Serial.println(F("Pressed"));
buttonPress= false;
} else {
Serial.println(F("Normal"));
}
delay(250);
}
void buttonPressed() {
//Set timer to work for your loop code time
if (millis() - buttonTime > 250) {
//button press ok
buttonPress= true;
}
buttonTime = millis();
}
See: https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware__irq.html for disable, enable etc.

STM32F412 using FreeRTOS and USB to do audio processing

I am using stm32f4 nucleuo board. I can transmit the audio data through usb to PC without FreeRTOS. Now I want to learn how to integrate the FreeRTOS and usb together. But I have some questions about how fundamentally threads and ISR interact with each other.
Below I have two files.
In main.c, there are two threads created.In usb_thread, I initialize usb dirver and do nothing else.
In vr_thread, it waits state == 1 and process PCM_Buffer.
/* main.c */
extern uint16_t PCM_Buffer[16];
int state = 0;
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
osThreadDef(usb_t, usb_thread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
osThreadDef(vr_t, vr_thread, osPriorityNormal, 0, configMINIMAL_STACK_SIZE);
usb_thread_handle = osThreadCreate (osThread(usb_t), NULL);
usb_thread_handle = osThreadCreate (osThread(vr_t), NULL);
osKernelStart();
for (;;) {}
}
static void usb_thread(void const *argument)
{
/*Do some initialization here.*/
for (;;) {}
}
static void vr_thread(void const *argument)
{
/*Do some initialization here.*/
for (;;) {
if (state == 1) {
state = 0;
process_buffer(PCM_Buffer);
}
}
}
In app.c, USB_AUDIO_CallBack will be called by usb ISR every 1 millisecond. It transmit PCM_Buffer to PC first because it is really important, then it changes state to 1.
/* app.c */
uint16_t PCM_Buffer[16];
extern int state;
void USB_AUDIO_CallBack(void) //It will be called by usb ISR every 10^-3 second.
{
Send_Audio_to_USB((int16_t *)(PCM_Buffer), NUM_AUDIO_BUF);
state = 1;
}
Here are my questions.
1. How to find out the unit counting tick of FreeRTOS? USB_AUDIO_CallBack will be
called every 1 millisecond, how to know FreeRTOS basic tick is faster or slower
than 1 millisecond. Is FreeRTOS tick equal to systick?
2. Let's assume the process time of process_buffer is less than 1 millisecond. What I want to accomplish here is described below
hardware trigger
|
usb ISR
|
USB_AUDIO_CallBack
|
state=1
|
vr_thread process_buffer
|
state=0, then wait for hardware trigger again.
I really doubt it is the correct way to do it. Or should I use suspend() and resume()?
3. Is using extern to declare global PCM_Buffer the correct way to pass variable between threads or should I use queue in FreeRTOS?
I know these questions are trivial but I really want to understand them. Any helpful document or website is welcome. Thanks.
To convert real time to systick you can use macro pdMS_TO_TICKS(xTimeInMS).
You can define your USB_AUDIO_CallBack also as a thread (or task) or paste the code from the callback to vr_thread (as your application works on only one processor). Then inside the USB ISR you can send a notification using function vTaskNotifyGiveFromISR and receive it inside vr_thread by calling ulTaskNotifyTake. After receiving the notification you can call Send_Audio_to_USB((int16_t *)(PCM_Buffer), NUM_AUDIO_BUF);
and then process_buffer(PCM_Buffer);. It is better to bring out the code from callback to task, because the ISR handler will finish it's job faster as Send_Audio_to_USB function could run long time. You also keep things to be executed in the same order as you needed.
I think that you mean volatile instead of extern. If you want to use this buffer along different threads and ISRs you should define it as volatile, but if you will use the approach with only one task you can declare this buffer as local buffer.

Arduino Bluetooth connection gives me uploading error

İt's a simple basic thing in which i have my arduino connected to a HC-06 bluetooth. The point is to control switch on/off led pin with my phone. Here's the code :
int ledPin = 13;
int state = 0;
int flag = 0;
void setup() {
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
Serial.begin(9600);
}
void loop() {
if(Serial.available() >0) {
state = Serial.read();
flag = 0;
}
if(state == '0') {
digitalWrite(ledPin, LOW);
Serial.println("LED: off");
flag = 1;
}
}
else if (state == '1') {
Serial.println("LED: on");
flag = 1;
}
}
I don't think it might have much relevance. Whenever i try to upload the code it gives me the following error:
avrdude stk500_recv() programmer is not responding
avrdude stk500_getsync() attempt # of 10 not in sync resp=0x00
Any idea why and how i might solve it. Thnx in advance!Douglas
I guess that there is a conflict between the USB/Serial and HC06/Serial.
You can solve this issue by using the Software Serial library and connect the HC06 to other pins. You can find an example here on how to use the library.
Unplug the rx and tx pins and keep in power and ground while uploading. When these pins are connected it interferes with the program's ability to upload. If this is in fact the problem then once the program is uploaded you can reattach rx and tx. Now you should be able to properly pair to your device.
Please disconnect the Tx and RX pin from Arduino before uploading and connect it after uploading the code. Otherwise, it will show an error

PIC16f877a USART Interrupt handling

I am trying to write a simple code to receive and resend data using usart but the code is not working. Can someone give suggestions on the possible flaws in the code.Please note that I am using USART at baud rate 9600 with clock frequency 4MHz.
#include<pic.h>
void main()
{ TRISB=0X00;
TXEN=1;
SYNC=0;
BRGH=1;
SPEN=1;
CREN=1;
//RCEN=1;
SPBRG=0X19;
INTCON=0X80;
TRISC7=1;
TRISC6=0;
RCIE=1;
TXIE=1;
while(1);
}
void interrupt rectrans()
{
if(RCIF==1)
{
TXREG=RCREG;
while(!TRMT);
RCIF=0;
}
else if(TXIF==1)
{TXIF=0;
}
}
I think you should enable GIE bit or Global Interrupt Enable bit for activating any interrupt as you can see from the attached diagram with this answer.. Try to add GIE=1; to enable global interrupt... You can see and AND gate to which GIE bit is connected only all any other interrupt will pass if GIE bit is high

GPS altitude print to LCD

I am trying to get my arduino uno to display the altitude from a GPS module, without any other data. I am still learning the code, but I've run into a problem where I can't seem to find what command is used to pull the altitude from the GPS string. I know it is pulling the data successfully, as I ran the example code from http://learn.parallax.com/kickstart/28500 and it read the first bit of the string, though I moved onto trying to get the altitude before getting it to scroll the whole string.
I am using a basic 16x2 LCD display, and the display I have working fine.
The end goal of this project is a GPS/gyroscope altimeter that can record to an SD card and record temperature, and deploy a parachute at apogee (15,000ft) and a larger parachute at 1,000ft.
Here is the code I am using for the altitude, I've marked the section I can't figure out. (probably just missing a term, or I might have really messed something up)
Any help would be appreciated, have a great day.
#include <SoftwareSerial.h>
#include "./TinyGPS.h" // Special version for 1.0
#include <LiquidCrystal.h>
TinyGPS gps;
SoftwareSerial nss(0, 255); // Yellow wire to pin 6
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
void gpsdump(TinyGPS &gps);
bool feedgps();
void setup() {
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// initialize the serial communications:
Serial.begin(9600);
Serial.begin(115200);
nss.begin(4800);
lcd.print("Reading GPS");
lcd.write(254); // move cursor to beginning of first line
lcd.write(128);
lcd.write(" "); // clear display
lcd.write(" ");
}
void loop() {
bool newdata = false;
unsigned long start = millis();
while (millis() - start < 5000) { // Update every 5 seconds
if (feedgps())
newdata = true;
}
gpsdump(gps);
}
// Get and process GPS data
void gpsdump(TinyGPS &gps) {
// problem area
float falt, flat, flon;
unsigned long age;
gps.f_get_position(&flat, &flon);
inline long altitude (return _altitude);
long _altitude
;lcd.print(_altitude, 4);
}//end problem area
// Feed data as it becomes available
bool feedgps() {
while (nss.available()) {
if (gps.encode(nss.read()))
return true;
}
return false;
}
lcd.print(x,4) prints base-4. Did you want that, or do you want ordinary base-10 (decimal)?
Secondly, where do you expect _altitude to come from? It's uninitialized. There's also an uninitialized falt, and a weird inline long altitude line which doesn't mean anything.
You might be better of learning C++ first, in a desktop environment. Debugging an embedded device is a lot harder, and you're still producing quite a few bugs.