On the i2c bus, Arduino Nano with address 2, transmits the weight value with a resolution of 1 kg.

Dependencies:   _24LCXXX

main.cpp

Committer:
Aleksk
Date:
2020-05-15
Revision:
2:8230a5a4cc13
Parent:
1:1d4ec28f17c4
Child:
3:712f751b4974

File content as of revision 2:8230a5a4cc13:

// Создан сторожевой таймер, который истекает через 100мс
#include "mbed.h"
#include "_24LCXXX.h"

I2C i2c(PB_9,PB_8);        // sda, scl
_24LCXXX eeprom(&i2c, 0x50);

AnalogIn analog_value(A0);                                                      //подключение аналогового входа A0
DigitalOut led(LED1);
DigitalOut digital_4(PB_5);                                                     //initialize digital pin 4 as an output (high pressure air bulb charge).
DigitalOut digital_7(PA_8);                                                     //initialize digital pin 7 as an output. (high pressure air bulb discharge
RawSerial pc(USBTX, USBRX, 115200);                                             // tx, rx for F411RE    in port command string
RawSerial plotter(PA_9, PA_10, 115200);                                         // tx, rx for F411RE    out port  for serial_plotter
EventQueue *queue = mbed_event_queue();                                         //инициализация очереди событий RTOS mbed5
Timer timer;                                                                    //инициализация таймера
//========УСТАВКИ========
uint8_t flag_autoset = 0;                                                       //отладочный флаг. При 0 - запрет автоуставки давления, при 1 - разрешение
uint8_t flag_plotter = 0;                                                       //отладочный флаг. При 0 - запрет печати в плоттер, при 1 - разрешение
int value = 0;                                                             //set begin value "pressure"   1...3300
uint8_t delta_value = 0;                                                        //set delta pressure 1...99
//=======================
int value_auto=250 ;                                                            //set begin value auto "pressure"
int sensor_value =0;                                                            //напряжение с аналогового входа А0 (текущее давление)
int counter_cycle1 = 0;                                                         //счётчик цикла while(true)
int counter_cycle2 = 0;                                                         //счётчик внутри функции auto_set
int sig = 1;                                                                    //знак инкримента для автоустаки
//                       FIFO_buffer must be full (only char  and '\0') 
//#define maxnsym 24                                                             // maximum nbr of symbols FIFO_buffer (вариант без символов окончания)
#define maxnsym 26                                     // maximum nbr of symbols FIFO_buffer +CR+LF (символы окончания должны быть включены на передаче)
char Source[maxnsym]="$press,1000,25,0,0,2050**";      //23 char- string ,весь массив со строкой для поиска 23+1(null terminal)=24 
                                                      //уставки и контрольная сумма умноженная на два, должны быть больше нуля  
char trueSource[maxnsym];                             //верифицированная строка для callback
char trueSourceOld[maxnsym];                          //предыдущая верифицированная строка для callback

volatile char chr_a;                                //в прерываниях переменные должны быть защищены  при помощи volatile от оптимизации компилятором
volatile bool flag_comand_detected = false;         //если строка декодирована правильно то true
volatile bool flag_stopRegulator = true;                    //флаг остановки , закрыть все клапана 
//_____________________________________________________________________________
void save_EEPROM () {
    int data2;
    pc.printf("EEPROM write------\r\n");    
    eeprom.byte_write(0, delta_value);
    eeprom.byte_write(1, flag_autoset);
    eeprom.byte_write(2, flag_plotter);
    data2 = value;
    eeprom.nbyte_write( 10, &data2, sizeof(int));
}
//_____________________________________________________________________________
void load_EEPROM () {
    uint8_t data1;
    int data2;
    pc.printf("EEPROM read------\r\n");
    eeprom.nbyte_read( 0, &data1, 1 );
    pc.printf("adress 0  =%d \r\n",data1);
    delta_value=data1;
    eeprom.nbyte_read( 1, &data1, 1 );
    pc.printf("adress 1  =%d \r\n",data1);
    flag_autoset=data1;
    eeprom.nbyte_read( 2, &data1, 1 );
    pc.printf("adress 2  =%d \r\n",data1);
    flag_plotter=data1;
    eeprom.nbyte_read( 10, &data2, sizeof(int) );
    pc.printf("adress 10  = %d \r\n",data2);
    value=data2;
    }
//______________________________________________________________________________
void substring(char *s,char *d,int pos,int len) {
//usage: substring(Source,Destination,pos,len);
    char *t;
    s=s+(pos-1);
    t=s+len;
    while (s!=t) {
        *d=*s;
        s++;
        d++;
    }
    *d='\0';
}
//______________________________________________________________________________
void onDataReceived();                                                          // callback
//______________________________________________________________________________ 
void read_serial(void) {
  char Destination[50];
  int pos,len;
  int controlSum1, controlSum2;
  int value_, delta_value_, flag_autoset_, flag_plotter_;
  int ch = '$';    // Код искомого символа
  int indexCh;       // Char on position
  char *ach;       // Указатель на искомую переменную в строке, по которой осуществляется поиск.
    while(pc.readable()) {
       chr_a = pc.getc();
       //_____FIFO_buffer_begin_____
       for ( int i = 2; i < maxnsym; i++) {
       Source[i-2]=Source[i-1];
       }
       Source[maxnsym-2]=chr_a;                     //предпоследний элемент
       Source[maxnsym-1] ='\0';                     //последний элемент массива это нуль-терминал для формирования конца строки в Си
       //_____FIFO_buffer_end_______
    }
   ach=strchr (Source,ch);   //поиск первого вхождения символа в строку , ищем указатель символа ‘$’
   if (ach==NULL) {
     //pc.printf ("Char  not finded \r\n");                   //Символ $ в строке не найден
     goto endParsing;        //пропускаем парсинг
   }
   else {
     indexCh = ach-Source+1;                                //вычитаем указатель из указателя!
     //pc.printf ("Char '$' on position  %d\r\n",indexCh);   //Искомый символ в строке на позиции 
   } 
   if (indexCh!=1) {                           //позиция символа $ не 1
     //pc.printf ("$ position not 1 \r\n");
     goto endParsing;       //пропускаем парсинг
   }
   
    pos=1;  //начало подстроки $press - на 1 позиции
    len=6;   //длина подстроки $press равна 6
    substring(Source,Destination,pos,len);
    //pc.printf("for pos=%d and  len=%d  resultat is  d= %s\r\n", pos, len, Destination);
    
    if (strcmp(Destination,"$press" ) != 0) {                                   //функция возвращает ноль если строки совпадают
      //pc.printf("wrong Destination=%s\r\n",Destination);                         //печать "неправильной" нулевой строки 
      goto endParsing ;                                                         //в начале сообщения нет $press пропускаем парсинг
    }
    pos=8;  //начало подстроки 1000 - на 8 позиции
    len=4;   //длина подстроки 1000 равна 4
    substring(Source,Destination,pos,len);
    value_=atoi(Destination);
    if (value_==0) {
      goto endParsing;       //уставка должна быть больше еденицы, пропускаем парсинг
    }
    //pc.printf("for pos=%d and  len=%d  resultat is  d= %s atoi=%d\r\n", pos, len, Destination, value_);
    pos=13;  //начало подстроки 25 - на 13 позиции
    len=2;   //длина подстроки 25 равна 2
    substring(Source,Destination,pos,len);
    delta_value_=atoi(Destination);
    if (delta_value_==0) {
      goto endParsing;       //уставка отклонения должна быть больше еденицы, пропускаем парсинг
    }
    //pc.printf("for pos=%d and  len=%d  resultat is  d= %s atoi=%d\r\n", pos, len, Destination, delta_value_);
    pos=16;  //начало подстроки 0 - на 16 позиции
    len=1;   //длина подстроки 0 равна 1
    substring(Source,Destination,pos,len);
    flag_autoset_=atoi(Destination);
    //pc.printf("for pos=%d and  len=%d  resultat is  d= %s atoi=%d\r\n", pos, len, Destination, flag_autoset_);
    pos=18;  //начало подстроки 0 - на 18 позиции
    len=1;   //длина подстроки 0 равна 1
    substring(Source,Destination,pos,len);
    flag_plotter_=atoi(Destination);
    //pc.printf("for pos=%d and  len=%d  resultat is  d= %s atoi=%d\r\n", pos, len, Destination, flag_plotter_);
    pos=20;  //начало подстроки 1025 - на 18 позиции
    len=4;   //длина подстроки 1025 равна 4
    substring(Source,Destination,pos,len);
    controlSum1=atoi(Destination);
    if (controlSum1==0) {
      goto endParsing;       //контрольная сумма должна быть больше еденицы, пропускаем парсинг
    }
    //pc.printf("for pos=%d and  len=%d  resultat is  d= %s atoi=%d\r\n", pos, len, Destination, controlSum1);
    controlSum2=(value_+delta_value_+flag_autoset_+flag_plotter_)*2;            //удвоение чтобы не было одинаковых чисел в сообщении
    //pc.printf("controlSum1=%d   controlSum2=%d\r\n", controlSum1, controlSum2);
    if (controlSum1!=controlSum2) {                                             //не совпала контрольная сумма
      //pc.printf ("controlSum1!=controlSum2 \r\n");
      goto endParsing;       //пропускаем парсинг
    }
    //присваиваем проверенные значения глобальным переменным
    strcpy(trueSource,Source);        //копировать из Source в trueSource
    value=value_;
    delta_value=delta_value_;
    flag_autoset=flag_autoset_;
    flag_plotter=flag_plotter_;
    flag_comand_detected=true;        //если флаг true, то всем переменным  присвоены новые значения уставок
    
 endParsing:   
    
        
pc.attach(&onDataReceived, Serial::RxIrq);                             // reattach interrupt - переподключение прерывания перед выходом из функции
}
//______________________________________________________________________________
void onDataReceived() {
    pc.attach(nullptr, Serial::RxIrq);                                          // detach interrupt
    queue->call(read_serial);                                                   // process in a non ISR context - переход к функции приема строки -
}                                                                               // - в статусе отключенного прерывания (учим указатели!)
//______________________________________________________________________________
void auto_set () {
    if (counter_cycle2 >= 100 && flag_autoset == 1) {
      counter_cycle2=0;
      if (value_auto > 2800 || value_auto < 250) {
        sig = -sig;                                                             //меняем знак для изменения направления роста/спада автоуставки
      } 
       value_auto = value_auto + sig * 250;
       value=value_auto;     
    }  
  counter_cycle2++;                                                             //увеличиваем счетчик функции auto_set() на 1
}
//*****************************************************************************
//***************************************************************************** 

int main() {
    
    pc.attach(&onDataReceived, Serial::RxIrq);
    int time, valve1, valve2, countValve1=0, countValve2=0;
    int frequencyValve1, frequencyValve2;
    float raw_value_sum = 0 ;
    digital_4.write(0);                                                         //valve1  off;
    digital_7.write(0);                                                         //valve2  off;                                         
    load_EEPROM ();                                                             //загрузка уставок из EEPROM
    if (value >= 1 && delta_value >= 1 && flag_autoset < 2 && flag_plotter < 2) {
      flag_stopRegulator=false;                                                 //уставки из EEPROM похожи на правду, разрешаем работу регулятора 
    } else {
      flag_stopRegulator = true;                                                //флаг остановки установлен 
      pc.printf("Regulator stopped, error in EEPROM \r\n");       
    }
      
    pc.printf("Program started \r\n");
    Watchdog &watchdog = Watchdog::get_instance();
    watchdog.start(100);                         //WDlimit = 100  ms
    timer.start();
    
  while (true){                                                                 //бесконечный цикл
    // kick watchdog regularly within provided timeout (сброс собаки в начало счёта)
    watchdog.kick();
    if (flag_comand_detected) {                                                 //пришла правильная командная строка
      pc.printf("$press,%d,%d,%d,%d,%d,%d,%d,*\r\n",
        value,delta_value,flag_autoset,flag_plotter,sensor_value,frequencyValve1,frequencyValve2);     //текущие данные
      //pc.printf("%s\r\n",trueSource);                                         //эхо для отладки канала связи
      flag_comand_detected=false;                                               //в последующих обращениях не печатать пока нет новых уставок из СОМ-порта
      flag_stopRegulator=false;                                                 //сброс флага,  регулятор ждет пока  не будет сброшен этот флаг
      //plotter.printf("$%d %d %d %d %d;\r\n", digital_4.read()*100-110,
      //  digital_7.read()*100-220, value, sensor_value, time );                //печать в плоттер в другой СОМ-порт
      if (strcmp(trueSourceOld,trueSource) != 0) {                              //функция возвращает ноль если командные строки совпадают
        save_EEPROM ();                                                         //пишем в память уставки отличные от старых
        load_EEPROM ();
      }
      
      strcpy(trueSourceOld,trueSource);        //копировать из trueSource в trueSourceOld 
    }
    float  raw_value = analog_value.read();                                     // Чтение аналогового входа (0.0 to 1.0 = full ADC диапазон)
    raw_value_sum = raw_value_sum + raw_value;
       
    if (counter_cycle1 > 20 ) {
      counter_cycle1=0;
      sensor_value = raw_value_sum/20 * 3300;                                   // преобразование в напряжение 0-3300 mV  с усреднением
      raw_value_sum = 0 ;
      if (flag_stopRegulator == false) {                                        // можно запускать регулятор
        //--------------regulator begin-----------------------
        if (sensor_value > value + delta_value) {
          valve2 = digital_7.read();
          digital_7.write(1);                                                     //valve2  on;
          if (valve2 < digital_7.read()) {countValve2++;}                         //счётчик передних фронтов напряжения (срабатывания клапана 2)
          digital_4.write(0);                                                     //valve1  off;
        } else  if (sensor_value < value - delta_value) {
          valve1 = digital_4.read();
          digital_4.write(1);                                                     //valve1  on;
          if (valve1 < digital_4.read()) {countValve1++;}                         //счётчик передних фронтов напряжения (срабатывания клапана 1)
          digital_7.write(0);                                                     //valve2  off; 
        } else {
          digital_4.write(0);                                                     //valve1  off;
          digital_7.write(0);                                                     //valve2  off; 
        }
        //--------------regulator end-------------------------
      }
      time=timer.read_us();
      if (time > 1000000) {
        timer.reset();                                                          //начало счёта времени
        frequencyValve1 =  countValve1;                                         //частота (Гц) срабатывания клапана 1 
        frequencyValve2 =  countValve2;                                         //частота (Гц) срабатывания клапана 2 
        countValve1=0;
        countValve2=0;
      }
      
      if (flag_plotter == 1) {
        plotter.printf("$%d %d %d %d %d %d;\r\n", digital_4.read()*100-110,
        digital_7.read()*100-220, value, sensor_value, 100*frequencyValve1, 100*frequencyValve2 );   //печать в плоттер в другой СОМ-порт (только для отладки)   
      }
    
      auto_set();                                                  //Ступенчатое увеличение и уменьшение уставки value (для отладки если flag_autoset =1)
      led = !led;                                                               //гасим/зажигаем индикаторный светодиод
    } 
    ThisThread::sleep_for(1);                                                   // (mc) правильный оператор задержки для mbed5
    counter_cycle1++;
    
  }
}