Зависает arduino nano
- Войдите на сайт для отправки комментариев
Пт, 23/01/2015 - 19:10
Доброго времени суток!
используя nrf24l01 отправляю запросы о состоянии "ножки" на МК arduino nano, каждые 3 секунды. примерно после 20 минут, 2-ой МК зависает и престает отвечать на запросы, думал с переполнение serial, отключил, но все равно зависает, подскажите пожалуйста, в чем может быть дело:
/*
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/*
Hack.lenotta.com
Modified code of Getting Started RF24 Library
It will switch a relay on if receive a message with text 1,
turn it off otherwise.
Edo
*/
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "printf.h"
int relay1 = 8;
int relay2 = 7;
//
// Hardware conf
//
// Set up nRF24L01 radio on SPI bus plus pins 9 & 10
RF24 radio(9,10);
//
// Topology
//
// Radio pipe addresses for the 2 nodes to communicate.
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
char * convertNumberIntoArray(unsigned short number, unsigned short length) {
char * arr = (char *) malloc(length * sizeof(char)), * curr = arr;
do {
*curr++ = number % 10;
number /= 10;
} while (number != 0);
return arr;
}
unsigned short getId(char * rawMessage, unsigned short length){
unsigned short i = 0;
unsigned short id = 0;
for( i=1; i< length; i++){
id += rawMessage[i]*pow( 10, i-1 );
}
return id;
}
unsigned short getMessage( char * rawMessage){
unsigned short message = rawMessage[0];
return (unsigned short)message;
}
unsigned short getLength( unsigned int rudeMessage){
unsigned short length = (unsigned short)(log10((float)rudeMessage)) + 1;
return length;
}
void setup(void)
{
//
// Print preamble
//
//Serial.begin(57600);
pinMode(relay1, OUTPUT);
digitalWrite(relay1, HIGH);
pinMode(relay2, OUTPUT);
digitalWrite(relay2, HIGH);
//printf_begin();
//printf("\nRemote Switch Arduino\n\r");
//
// Setup and configure rf radio
//
radio.begin();
// radio.setAutoAck(1); // Ensure autoACK is enabled
radio.setRetries(15,15);
radio.setDataRate(RF24_2MBPS);
radio.openWritingPipe(pipes[1]);
radio.openReadingPipe(1,pipes[0]);
radio.startListening();
//radio.printDetails();
}
int getState(unsigned short pin){
boolean state = digitalRead(pin);
return state == true ? 0 : 1;
}
void doAction(unsigned short id, unsigned short action){
if( action == 0 ){
digitalWrite(id, HIGH);
}else{
digitalWrite(id, LOW);
}
}
void sendCallback(unsigned short callback){
// First, stop listening so we can talk
radio.stopListening();
// Send the final one back.
radio.write( &callback, sizeof(unsigned short) );
//printf("Sent response.\n\r");
// Now, resume listening so we catch the next packets.
radio.startListening();
}
void performAction(unsigned short rawMessage){
unsigned short action, id, length, callback;
char * castedMessage;
length = getLength(rawMessage);
castedMessage = convertNumberIntoArray(rawMessage, length);
action = getMessage(castedMessage);
id = getId(castedMessage, length);
if (action == 0 || action ==1){
callback = action;
doAction(id, action);
}else if(action == 2){
callback = getState(id);
}
sendCallback(callback);
}
void loop(void)
{
// if there is data ready
if ( radio.available() )
{
// Dump the payloads until we've gotten everything
unsigned short message;
bool done;
// char * new;
unsigned short rawMessage;
done = false;
while ( radio.available() )
{
// Fetch the payload, and see if this was the last one.
radio.read( &rawMessage, sizeof(unsigned long) );
// Spew it
//printf("Got message %d...",rawMessage);
performAction(rawMessage);
//delay(2);
Serial.flush();
}
}
}
1. Кросспост это нехорошо.
2. Может поможет, если перевести на библиотеку MIRF.
Из любопытства: а что оно посылает назад? И как в посылке обозначены включения релюх? Другими словами - протокол в студию.
IMNSHO, стримы, трубы, callback какой-то... По-мне, этот скетч слишком прост, чтобы устраивать себе такой ад.
с первого МК отправляется "2", запрашивая состояние пина, второй МК в свою очередь посылает исключительно либо "0" либо "1" этим и обозначены включения релюх, если 0 значит выключено, если 1 включено соответственно
Оба? Всмысле 00 обе выкл, 10 первая вкл вторая выкл, или тупо 0 1?
И что вызывает doAction? Первый МК может прислать команду, типа включи вторую релюху, или он только посылает цифру 2, спрашивая состояние?
С первого МК можно включить и выключить оба канала релюхи и запросить состояния обоих (по отдельности):
команда remote -m 71 включает на втором МК канал реле №1 (пин 7)
команда remote -m 81 включает на втором МК канал реле №1 (пин 8)
команда remote -m 72 получает со второго МК состояние канала реле №1 (1 - если включен, 0 - если выключен)
команда remote -m 82 получает со второго МК состояние канала реле №2 (1 - если включен, 0 - если выключен)
Далее код с первого МК:
#include <string> #include <getopt.h> #include <cstdlib> #include <sstream> #include <iostream> #include <RF24/RF24.h> using namespace std; //RF24 radio("/dev/spidev0.0",8000000 , 25); //RF24 radio(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ); RF24 radio(RPI_V2_GPIO_P1_22, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ); //const int role_pin = 7; const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; //const uint8_t pipes[][6] = {"1Node","2Node"}; // hack to avoid SEG FAULT, issue #46 on RF24 github https://github.com/TMRh20/R F24.git unsigned long got_message; void setup(void){ //Prepare the radio module // printf("\nPreparing interface\n"); radio.begin(); radio.setRetries( 15, 15); radio.setDataRate(RF24_2MBPS); // radio.setChannel(0x4c); radio.setPALevel(RF24_PA_MAX); //radio.printDetails(); radio.openWritingPipe(pipes[0]); radio.openReadingPipe(1,pipes[1]); // radio.startListening(); } bool sendMessage(int action){ //This function send a message, the 'action', to the arduino and wait fo r answer //Returns true if ACK package is received //Stop listening radio.stopListening(); unsigned long message = action; //printf("Now sending %lu...", message); //Send the message bool ok = radio.write( &message, sizeof(unsigned long) ); if (!ok){ printf("failed...\n\r"); }else{ printf(""); } //Listen for ACK radio.startListening(); //Let's take the time while we listen unsigned long started_waiting_at = millis(); bool timeout = false; while ( ! radio.available() && ! timeout ) { //printf("%d", !radio.available()); if (millis() - started_waiting_at > 1000 ){ timeout = true; } } if( timeout ){ //If we waited too long the transmission failed printf("0"); return false; }else{ //If we received the message in time, let's read it and print it radio.read( &got_message, sizeof(unsigned long) ); printf("%lu",got_message); return true; } } int main( int argc, char ** argv){ char choice; setup(); bool switched = false; int counter = 0; //Define the options while(( choice = getopt( argc, argv, "m:")) != -1){ if (choice == 'm'){ // printf("\n Talking with my NRF24l01+ friends out there.. ..\n"); while(switched == false && counter < 1){ switched = sendMessage(atoi(optarg)); counter ++; sleep(1); } }else{ // A little help: printf("\n\rIt's time to make some choices...\n"); printf("\n\rTIP: Use -m idAction for the message to send . "); printf("\n\rExample (id number 12, action number 1): "); printf("\nsudo ./remote -m 121\n"); } //return 0 if everything went good, 2 otherwise if (counter < 5) return 0; else return 2; } }Предлагаю так:
Передатчик (тот кто спрашивает и включает/выключает):
#include <SPI.h> #include <Mirf.h> #include <nRF24L01.h> #include <MirfHardwareSpiDriver.h> byte data[2]; // посылка void setup(){ Mirf.spi=&MirfHardwareSpi; Mirf.cePin=9; Mirf.csnPin=10; Mirf.init(); Mirf.setRADDR((byte *)"clien"); // принимаем на адрес "clien" т. к. мы клиент Mirf.setTADDR((byte *)"servr"); Mirf.payload=2; Mirf.channel=1; Mirf.config(); } void setstate(boolean relay1, boolean relay2){ data[0]=relay1; data[1]=relay2; Mirf.send(data); while(Mirf.isSending()){} delay(10); } void ackstate(){ data[0]=2; // первый байт - двойка, второй пох Mirf.send(data); while(Mirf.isSending()){} delay(10); } void loop(){ if(!Mirf.isSending() && Mirf.dataReady()){ Mirf.getData(data); // data[0] - состояние relay1 // data[1] - состояние relay2 } // ackstate(); - послать запрос на состояние // setstate(0,1); - установить состояние }Приёмник:
#include <SPI.h> #include <Mirf.h> #include <nRF24L01.h> #include <MirfHardwareSpiDriver.h> int relay1=8; int relay2=7; byte data[2]; // посылка void setup(){ Mirf.spi=&MirfHardwareSpi; Mirf.cePin=9; Mirf.csnPin=10; Mirf.init(); Mirf.setRADDR((byte *)"servr"); // принимаем на адрес "servr" т. к. мы - сервер Mirf.setTADDR((byte *)"clien"); Mirf.payload=2; // размер посылки, 2 байта Mirf.channel=1; Mirf.config(); } void loop(){ if(!Mirf.isSending() && Mirf.dataReady()){ Mirf.getData(data); if(data[0]==2){ // есть двойка, посылаем состояние data[0]=digitalRead(relay1); data[2]=digitalRead(relay2); Mirf.send(data); // отправка while(Mirf.isSending()){} // ничё не делаем, пока отправляется delay(10); // на всякий пожарный }else{ // не двойка if(data[0]<2) // защита от дурака, вдруг отправят 3 или больше digitalWrite(relay1,data[0]); // делаем что надо, ноль выключит, единица включит if(data[1]<2) // то же самое для второй digitalWrite(relay2,data[1]); } } }Останется только прикрутить работу с командной строкой, т. к. я в этом не соображаю.
Библиотека
Чтобы трансивер передавал на максимальной мощности, с максимальной чувствительностью на 250 кбит/с, надо сделать Mirf.configRegister(0x06, 0b00100110); после Mirf.config();
Скажите, а это библиотека разве будет работать на Raspberry Pi, потомучто первый МК это это он, а второй МК Arduino Nano а общаются они через nrf24l01
Версия для RPi.
Но вообще по-идее можно ничего там не менять, т. к. висла именно нано. Ей лишь нужно посылать то чего от неё ждут циклы клиента. Без разницы каким способом и какой библиотекой. Главное чтобы настройка совпадала - канал, адреса, скорость, размер посылки. Если длина посылки у Raspberry неизвестна - выяснить.
UPD
А, ну и фраза radio.read( &rawMessage, sizeof(unsigned long) ); какбе намекает на payload=4
Большое спасибо! значит, Вы думаете, что дело в библиотеке для arduino? что она зависает
Как вариант. Гадаю т. к. не приходилось крутить. Мне понятнее Mirf.
Другие факторы - аппаратные. Типа нету диода поперёк обмотки реле. Но от таких вещей ардуина обычно сбрасывается. А у вас если не было такого что 10-20 секунд тупка а потом работа восстанавливается, значит проблема программная.
еще раз спасибо, попробую, отпишусь