I have the following sketch, and the numTicks variable is not incrementing, the sketch compiles fine to the Arduino, but for whatever reason the variable "numTicks" is not incrementing.
/*
* kegboard-clone-4-KegCop
* This code is public domain
*
* This sketch sends a receives a multibyte String from the iPhone
* and performs functions on it.
*
* This Arduino sketch is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Public License
* along with this sketch. If not, see <http://www.gnu.org/licenses/>.
*
* Examples:
* http://arduino.cc/en/Tutorial/SerialEvent
* http://arduino.cc/en/Serial/read
* http://stackoverflow.com/questions/16532586/arduino-sketch-that-responds-to-certain-commands-how-is-it-done/
* http://davebmiller.wordpress.com/2011/01/18/arduino-flowmeter/
* http://forum.arduino.cc/index.php?topic=52003.0
* http://arduino.cc/en/Reference/AttachInterrupt
* https://github.com/just-kile/Zapfmaster2000/blob/master/src/zapfmaster2000-zapfkit-avr/draftkitAVR.ino
*
* TODO:
* - eventually get code working with the SF800 flow sensor / flowmeter
*
*/
// flow_A LED
int led = 4;
// relay_A
const int RELAY_A = A0;
// string / serial event variables
String inputString = ""; // a string to hold incoming data
boolean stringComplete = false; // whether the string is complete
boolean valve_open = false;
// FLOWMETER SHIT
// flowmeter 0 pulse (input) = digital pin 2
// https://github.com/Kegbot/kegboard/blob/master/arduino/kegboard/kegboard_config.h
// which pin to use for reading the sensor? kegboard-mini shield has digital pin 2 allocated
// the SF800 outputs 5400 pulses per litre
// The hall-effect flow sensor (SF800) outputs approximately 5400 pulses per second per litre/minute of flow
// SF800 default (5400 ticks/Liter == 5.4 ticks/mL == 1/5.4 mL/tick)
int flowmeterInterrupt = 0; // changed from byte
int flowmeterPin = 2; // changed from byte
int flowmeterPinState = 0; // variable for storing state of sensor pin
// read RPM
int rpmcount = 0;
int rpm = 0;
unsigned long lastmillis = 0;
// NEW GLOBALS - 29JUL13
// initial ticks on flow meter
volatile unsigned int numTicks = 0;
// interval for flow meter frequency
int interval = 250;
volatile long previousMillis = 0;
void setup() {
// initialize serial
// Serial.flush(); // flush the serial buffer on setup.
Serial.begin(115200); // open serial port, sets data rate to 9600bps
Serial.println("Power on test");
inputString.reserve(200);
valve_open = false;
// relay for solenoid cut off valve
pinMode(RELAY_A, OUTPUT);
// flowmeter shit
pinMode(flowmeterPin, INPUT);
digitalWrite(flowmeterPin, HIGH); // Need to set these HIGH so they won't just tick away
// The Hall-effect sensor is connected to pin 2 which uses interrupt 0.
// Configured to trigger on a RISING state change (transition from HIGH
// state to LOW state)
attachInterrupt(flowmeterInterrupt, count, RISING);
}
void open_valve() {
digitalWrite(RELAY_A, HIGH); // turn RELAY_A on
valve_open = true;
}
void close_valve() {
digitalWrite(RELAY_A, LOW); // turn RELAY_A off
valve_open = false;
}
void flow_A_blink() {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for one second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
void flow_A_blink_stop() {
digitalWrite(led, LOW);
}
void flow_A_on() {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
}
void flow_A_off() {
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
}
// flowmeter shit
void getFlow4() {
// Serial.println("im here");
// Serial.println(sensorPin);
flowmeterPinState = digitalRead(flowmeterPin);
// Serial.println(sensorPinState);
volatile unsigned long currentMillis = millis();
// if the predefined interval has passed
if(currentMillis - previousMillis > interval) { // Uptade every 1/4 second, this will be equal to reading frecuency (Hz).
// disconnect flow meter from interrupt
detachInterrupt(flowmeterInterrupt); // Disable interrupt when calculating
// check, whether any flow was detected
if (numTicks >= 0) {
// start message to computer with tick message symbol
Serial.print("Ticks:");
// send amount of ticks for last interval
Serial.print(numTicks);
}
// clean buffer
Serial.flush();
// reset amount of ticks
numTicks = 0;
// set new start value for interval counter
previousMillis = currentMillis;
// reattach interrupt
attachInterrupt(flowmeterInterrupt, count, RISING);
}
if(flowmeterPinState == LOW) {
flow_A_off();
// Serial.println("don't blink");
}
if(flowmeterPinState == HIGH) {
flow_A_on();
// Serial.println("blink damnit");
}
if(stringComplete) {
if(inputString.equals("{close_valve}\n")) {
// Serial.println("close vavle.");
close_valve();
}
return;
}
}
// flow meter interrupt function
void count(){
numTicks++;
}
/*
* Main program loop, runs over and over repeatedly
*/
void loop() {
if(stringComplete) {
// Serial.println(inputString);
if(inputString.equals("{open_valve}\n")) {
// Serial.println("inputString equates :)");
open_valve();
}
if(inputString.equals("{close_valve}\n")) {
// Serial.println("close vavle.");
close_valve();
}
if(valve_open) {
// Serial.println("valve_open = true");
inputString = "";
stringComplete = false;
while(numTicks <= 1000) {
getFlow4();
}
}
// clear the string:
inputString = "";
stringComplete = false;
}
//Serial.println("over and over");
}
/*
SerialEvent occurs whenever a new data comes in the
hardware serial RX. This routine is run between each
time loop() runs, so using delay inside loop can delay
response. Multiple bytes of data may be available.
*/
void serialEvent() {
while(Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
stringComplete = true;
}
// Serial.println(inputString.length());
}
}
The reason the numTicks variable is not changed is probably due to the interrupt not triggering. You should put a breakpoint in count() to confirm this. Then you need to figure out why the interrupt isn't triggering as it should, but that is another question.
Sorry for my prior answer. I did not completely understand the problem.
First of all, are you using an Arduino UNO, if so then check the board pin labelled digital pin 2 which is mapped as "int.0" and ensure that the interrupt line from the flowmeter is connected to this pin. (see: http://arduino.cc/en/Reference/AttachInterrupt).
Per Chris' comments above, the count() routine is interrupt driven code, and it appears to be coded correctly: numTicks is defined as volatile; and count() does NOT issue I/O commands such as printf; and it does NOT return any values.
The code sample that you provide does not isolate or highlight the problem. I would write a test sketch that is just a bare bones implementation of "opening" the sensor and then sensing an interrupt from the flow meter and reporting that back to the console from the main loop. If you can get code that detects one interrupt from the flow meter to work, then add more code to report on the number of interrupts in one second, then 1/2 second, etc.
Finally, in your provided code you have the fragment:
if(valve_open) {
// Serial.println("valve_open = true");
inputString = "";
stringComplete = false;
while(numTicks <= 1000) {
getFlow4();
}
}
Since numTicks is incremented by the interrupt routine count, as a matter of principal I would NOT test it unless some of kind of serialization was implemented. getFlow4() detaches the interrupt which is one way to serialize access to numTicks. Note. in theory code can update numTicks without serialization but any value returned is not necessarily accurate as the interrupt might have fired and increased numTicks.
It seems like your application is interested in knowing the number of ticks per second?? in which case you do NOT need to test numTicks prior to stopping the interrupts. All you might need is code that once every second checks numTicks and if you can live with dropping a count then zero out numTicks without even detaching the interrupt. However, sampling numTicks is more like polling which is what an interrupt is trying to avoid.
So, since the code is keeping track of intervals then divide the interval by numTicks to get a Hz value and don't zero out numTicks or reset the interval until they get close to rolling over.
The code ended up working, it was hardware issue with the connections from the flowmeter (>.>)
You are never actually calling your count() method. You should either insert numTicks++; into the code where you wish to increase the count (recommended way), or call your count() method where you wish to increase the count. Here the count() method is only defined and not called, but it would make more sense to just increment the counter in the code since that is the only thing your defined method is doing.
Related
I'm trying to keep a led ON while PIC is receiving a character (while a button is pressed), the led being OFF by default, but I can't seem to find a solution.
I'm 3 months in learning using microcontrollers (specifically PIC) coding with MPLABX IDE and started understanding UART communication. At first I tried turning a led ON/OFF when a charater is received, it went pretty good and worked, but right now I'm trying to keep a led active while a button is pressed but can't really get over this problem. I have my code in a interrupt function like this :
//#define LED RB5
void __interrupt () ISR (void)
{
if(RCIF) // data is received
{
data = RCREG; // get the value
if (data == '1') // if value received is '1'
LED = 1; //turn ON led
RCIF = 0;
}
LED = 0; // turn OFF led
}
Using the above code makes so the led turns on/off really fast while I keep pressing a button and isn't really what I wanted.I hope someone can help me understand what I need to do. Thanks !
The LED goes off quickly because you switch if off immediately after switching it on:
void __interrupt () ISR (void)
{
if(RCIF) // data is received
{
data = RCREG; // get the value
if (data == '1') // if value received is '1'
LED = 1; //turn ON led
RCIF = 0;
}
LED = 0; // turn OFF led <<=== This is executed unconditionally.
}
You might put LED = 0; in an else branch if you don't want it to be executed everytime.
Maybe like this:
void __interrupt () ISR (void)
{
if(RCIF) // data is received
{
data = RCREG; // get the value
if (data == '1') // if value received is '1'
LED = 1; //turn ON led
else
LED = 0; // turn OFF led
RCIF = 0;
}
}
Depending on your logic, the else might be placed after the end of the outer if block.
The LED goes off quickly after receiving any character.
RCIF flag will only set if UART data is received. So to turn off the LED you should start a timer of certain millisec and unless your reception is completed keep on restarting the timer.
void __interrupt () ISR (void)
{
if(RCIF) // data is received
{
data = RCREG; // get the value
if (data == '1') // if value received is '1'
LED = 1; //turn ON led
RCIF = 0;
start_timer_interrupt(x_ms); //set x_ms optimum timing so as to LED ON is visable with UART Rx
flag_rx_timer=1;
}
if(TIMER_OVERFLOW) //TIMER_OVERFLOW is an example keyword used here. Pleas add exact timer overflow flag
{
if(flag_rx_timer) //check if timer overflow is because of timer started during UART Rx
{
LED = 0;
flag_rx_timer=0;
}
}
}```
I suggest you create a state machine for this in app.c.
Define some states with an enum and a struct to hold the state and place them in app.h, include app.h in files where you wish to use this module (e.g. your system_interrupt.c file).
For example you could do this:
typedef enum{
IDLE,
START_RECEIVING,
STILL_RECEIVING,
}uart_state_t;
typedef struct{
uart_state_t current_state;
}uart_module_t
volatile uart_module_t uart_module = {0}; // initial state = IDLE, needs to be volatile because it will be updated via interrupt
Then create a function to service your state machine. This will handle the state that it is currently in and transition to other states as desired. For instance, the state machine starts in the IDLE state but once your interrupt has fired and RCIF bit is set then you'll transition in to the START_RECEIVING state which will turn the LED on then transition to the STILL_RECEIVING state where it will poll the RCIF bit until cleared. That would look something like this:
void uartFSM(void){
switch(uart_module.current_state){
case IDLE:
{
break;
}
case START_RECEIVING:
{
LED = 1; // Turn LED on
uart_module.current_state = STILL_RECEIVING; // state update
break;
}
case STILL_RECEIVING:
{
if(!RCIF){
// done receiving
LED = 0; // Turn LED off
uart_module.current_state = IDLE; // state update
}
break;
}
default:
{
// whoops
break;
}
}
}
Now your interrupt will look like this:
void __interrupt () ISR (void)
{
if(RCIF) // data is received
{
data = RCREG; // get the value
// if value received is '1'
if (data == '1') uart_module.current_state = START_RECEIVING; // state update
}
}
Now you just have to make sure that you call the uartFSM() some where in APP_Tasks so that the state machine gets serviced.
I've been struggling with some code lately. Just like I mentioned in my question, I want to loop a single section of code under the loop() block only once. I have done my research and am aware of the two common ways to do this. One is to put the code I want to run once in the setup() block and the second being using the while(1) statement in the loop() block. Unfortunately, both ways are not suitable for my code. The first reason is it is compulsory for my code to be in the loop() section. I cannot use the second option as all the code under the loop() block ends up running once. Like I said before, I want only a section of code in the loop() block to run once.
For your information, the purpose of this code is to display in an LCD, the amount of milliliters left for the user to drink for a healthy water consumption. For example, a person should drink min 1800ml a day for proper hydration. If the user drinks 123ml of water, LCD should display (1800-123).
//Adds the liquid crystal library
#include <LiquidCrystal.h>
//defines lcd pin numbers
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
// defines ultra sonic sensor pin numbers
const int trigPin = 8;
const int echoPin = 7;
// defines variables
long duration;
long volume;
long interval = 3600000; //1 hour
unsigned long stime = millis();
double pdist = 0;
double cdist = 0;
double mcons = 4.5; //128ml;
void setup() {
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
Serial.begin(9600); // Starts the serial communication
lcd.begin(16, 2); // Starts the lcd communication
}
void loop() {
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
//Converting the distance to cm
double cdist = duration / 29 / 2;
//Finding volume of the water
double volume_of_rem_height = 3.14*3*3*(cdist);
Serial.println(1800-volume_of_rem_height);
//I WANT ONLY THE BELOW STATEMENT TO BE RUN ONCE. REST ALL SHOULD CONTINUE
//TO LOOP.
lcd.print(1800-volume_of_rem_height);
The Arduino ruleas are easy:
Everything you want to be done exactly once when the Arduino is switched on, needs to go into init
Everything else neeeds to go into loop(at least, into loop's callchain.)
If you want something not done on every iteration on loop, stop the Arduino doing that by explicitly checking
Init two values of variables in init:
currentValue = lastValue = 0;
In loop, check whether something has changed from the last iteration, if yes, do the display update:
currentValue = 1800 - volume_of_rem_height
if (currentValue != lastValue) {
lastValue = currentValue;
lcd.print (currentValue)
}
This will only do the print once currentValue has really changed from the last iteration.
There seems to be a conflict between timer 2 and timer 3. This is a MIPS board and instead of using assembly language to program; I am using C. Timer1 is for a count which works properly. Timer2 is for a blinking LED which works properly. Timer3 is for switching count directions. But there is a conflict between timer2 and timer3. Does anyone know where the conflict is? I have to comment out DelayInit3(); in order for the code to execute properly.
void __ISR(_TIMER_2_VECTOR, ipl2) Timer2Handler(void)
{
// clear the interrupt flag
mT2ClearIntFlag();
PORTToggleBits(IOPORT_B, BIT_10);
}
void __ISR(_TIMER_23_VECTOR, ipl2) Timer23Handler(void)
{
// clear the interrupt flag
mT3ClearIntFlag();
if (direction != 0){
direction < 1;
}
else{
direction != 0;
}
}
int main()
{
DeviceInit();
DelayInit1();
DelayInit2();
// DelayInit3();
}
void DelayInit1()
{
unsigned int tcfg1;
/* Configure Timer 1. This sets it up to count a 10Mhz with a period of 0xFFFF
*/
tcfg1 = T1_ON|T1_IDLE_CON|T1_SOURCE_INT|T1_PS_1_8|T1_GATE_OFF|T1_SYNC_EXT_OFF;
OpenTimer1(tcfg1, 0xFFFF);
}
void DelayInit2()
{
unsigned int tcfg2;
// Config Timer 2. This sets it to count 312500 Hz with a period of T2_TICK
tcfg2 = T2_ON | T2_SOURCE_INT | T2_PS_1_32;
OpenTimer2(tcfg2, T2_TICK);
// Now enable system-wide multi-vector interrupt handling
INTEnableSystemMultiVectoredInt();
// Configure timer 2 interrupt with a priority of 2
ConfigIntTimer2(T2_INT_ON | T2_INT_PRIOR_2);
// Clear interrupt flag
mT2ClearIntFlag();
}
void DelayInit3()
{
unsigned int tcfg3;
// Config Timer 3. This sets it to count 312500 Hz with a period of T3_TICK
tcfg3 = T3_ON | T3_SOURCE_INT | T3_PS_1_256;
OpenTimer23(tcfg3, T23_TICK);
// Now enable system-wide multi-vector interrupt handling
INTEnableSystemMultiVectoredInt();
// Configure timer 3 interrupt with a priority of 2
ConfigIntTimer23(T23_INT_ON | T23_INT_PRIOR_2);
// Clear interrupt flag
mT3ClearIntFlag();
}
You should also toggle the bits at every timer end. The order that you are toggling is wrong. At every timer finish, you are toggling BIT10 twice, i.e. getting it back to initial position.
You can use code like this.
count = 0; // in Init.
while(1)
{
if (IFS0bits.T2IF == 1)
{
//if timer == period, toggle the LED
count++;
PORTToggleBits(IOPORT_B, BIT_10);
if (count %2 == 0)
{
DelayMs(2);
PORTToggleBits(IOPORT_B, BIT_11);
}
if (count > 3)
count = 0;
mT2ClearIntFlag();
}
}
You are toggleing the Bit 10 with a delay of 2 ms to it's first state. Even if this works, you will not notice.
Currently I'm working on a project where I have to read out pulses from a Arduino and check if the result is High or Low.
I had to write my own code to generate the high/low output from the Arduino:
//Pulse Generator Arduino Code
int potPin = 2; // select the input pin for the knob
int outputPin = 13; // select the pin for the output
float val = 0; // variable to store the value coming from the sensor
void setup() {
pinMode(outputPin, OUTPUT); // declare the outputPin as an OUTPUT
Serial.begin(9600);
}
void loop() {
val = analogRead(potPin); // read the value from the k
val = val/1024;
digitalWrite(outputPin, HIGH); // sets the output HIGH
delay(val*1000);
digitalWrite(outputPin, LOW); // sets the output LOW
delay(val*1000);
}
It uses a knob to change the delay between the pulses.
Im currently trying to read the high/low data with another Arduino (Lets call this one the "count Arduino") by simply connecting the 2 with the a cable from the "outputPin" to a port on the count Arduino.
I'm using digitalRead to read the port without any delay.
//Count Arduino Code
int sensorPin = 22;
int sensorState = 0;
void setup() {
pinMode(sensorPin, INPUT);
Serial.begin(9600);
}
void loop(){
sensorState = digitalRead(sensorPin);
Serial.println(sensorState);
}
First it tried with a pulse every 1 second but the result was a spam of a ton of lows and highs. Always 3 Lows and 3 highs and repeating. It wasn’t even close to one every 1 second but more like 1 every 1 millisecond.
I cant figure out what i'm doing wrong. Is it timing issue or is there a better way to detect these changes?
a spam of a ton of lows and highs
... happens if the GND of the two Arduinos are not connected.
Also, your reading arduino prints at every loop cycle, which were a few microseconds only, if the Serial buffer would not overflow.
Better printout changes only, or use a led to show what's happening.
void loop(){
static bool oldState;
bool sensorState = digitalRead(sensorPin);
if (sensorState != oldState) {
Serial.println(sensorState);
oldState = sensorState;
}
}
first code:
//------------------------------------------------------------------------------
/// Interrupt handlers for TC interrupts. Toggles the state of LEDs
//------------------------------------------------------------------------------
char token = 0;
void TC0_IrqHandler(void) {
volatile unsigned int dummy;
dummy = AT91C_BASE_TC0->TC_SR;
if(token == 1) {
PIO_Clear(&leds[0]);
PIO_Set(&leds[1]);
token = 0;
}
else {
PIO_Set(&leds[0]);
PIO_Clear(&leds[1]);
token = 1;
}
}
//------------------------------------------------------------------------------
/// Configure Timer Counter 0 to generate an interrupt every 250ms.
//------------------------------------------------------------------------------
void ConfigureTc(void) {
unsigned int div;
unsigned int tcclks;
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_TC0; // Enable peripheral clock
TC_FindMckDivisor(1, BOARD_MCK, &div, &tcclks); // Configure TC for a 4Hz frequency and trigger on RC compare
TC_Configure(AT91C_BASE_TC0, tcclks | AT91C_TC_CPCTRG);
AT91C_BASE_TC0->TC_RC = (BOARD_MCK / div) / 1; // timerFreq / desiredFreq
IRQ_ConfigureIT(AT91C_ID_TC0, 0, TC0_IrqHandler); // Configure and enable interrupt on RC compare
AT91C_BASE_TC0->TC_IER = AT91C_TC_CPCS;
IRQ_EnableIT(AT91C_ID_TC0);
printf(" -- timer has started \n\r");
TC_Start(AT91C_BASE_TC0);
}
it's just interrupt timer and it's event (handler) but when I run some
while(1) {
// action
after ConfigureTc() it both cycle and interrupt timer are freezes... Why could that be? Should I add another timer and avoid while(1) ?
while(1) {
printf("hello");
}
-- this breaks (freeze) loops (yes, if I don't use timer it works as it must)
I'll venture an actual answer here. IME, 99% of the time my boards 'go out' with no response on any input and no 'heartbeat' LED-flash from the low-priority 'blinky' thread, the CPU has flown off to a prefetch or data abort handler. These handlers are entered by interrupt and most library-defined default handlers do not re-enable interrupts, so stuffing the entire system. Often, they're just endless loops and, with interrupts disabled, that's the end of the story:(
I have changed my default handlers to output suitable 'CRITICAL ERROR' messages to the UART, (by polling it - the OS/interrupts are stuft!).