Control de bomba de pozo semiautomático utilizando STM32 en entorno Arduino

Muchos propietarios de parcelas domésticas tienen pozos de agua en sus posesiones, y pueden haber encontrado el problema de la sedimentación de un pozo / descomposición del agua durante el tiempo de inactividad de un pozo desde el otoño hasta la primavera.
Dio la casualidad de que el pozo en mi área permaneció inactivo durante varios años, y cuando se usó, se tomó muy poca agua.
Tratando de limpiarlo de varias maneras, se logró entender que no todo estaba tan mal y que era suficiente para asegurar una extracción de agua estable. Para hacer esto, se ensambló un dispositivo simple, que consta de una unidad de fuente de alimentación con un adaptador micro-usb, (no hay cargador de batería del teléfono, en la foto), un tablero de pastillas azul basado en el guijarro stm32f103c8t6, un módulo de relé, un arrancador magnético bipolar, un interruptor de botón cerrado convencional, y ensamblado en la caja de conexiones.
La placa del microcontrolador se preparó de acuerdo con el
manual de HWman . En los comentarios, hubo una solicitud para aclarar que STM32 se puede flashear con un cargador de arranque especial, que posteriormente le permite programarlo a través de USB, como arduinki ordinario.
Programo usando un
complemento en Visual Studio Community. Instalar el complemento es primitivo, no habrá trabajo mental. Solo agregaré que el complemento requiere el IDE ARDUINO instalado. Creo que los profesionales se sentirán avergonzados por este enfoque, pero el producto terminado ha estado funcionando de manera estable durante más de seis meses y cumple con la tarea. Y, sin embargo, estoy abierto a la cooperación en ideas para mejorar el dispositivo.
Obtenemos un entorno extremadamente conveniente con análisis de código, IntelliSense y lo que es subjetivamente importante: un tema oscuro. Para pequeños ojos.
Coser una bufanda:
Código/* Name: Nasos.ino Created: 23.02.2017 19:08:20 Author: Ksiw , () . , 10 . , , , 20 /. 99% delay() */ unsigned long Work = 2UL*60; /*2 */ // , // ... ! . const unsigned long Sleep = (unsigned long)20*60; // unsigned long TimeLeft; // int tempo = iter; // int iter = 10; // unsigned long timeNextSwich; int button = PB4; // unsigned long WorkTime, SleepTime ; // bool handOn = false; // bool flag; // int RelayPin = PB7; // unsigned long PreviousMillis = 0; unsigned long CurrentMillis = millis(); unsigned long fullTimeIteration = 4200000000; // //(long 4,294,967,295) //--------------------- void SwichFlag(); void SwichRelay(); void Button(); unsigned long SecToMillis(unsigned long); void ResidueTime(); void ResetTimeToWork(); //------------------------------------- --------------------------- void(*resetFunc) (void) = 0; //*************************************************************************** void setup() { Serial.begin(115200); flag = false; // //----------- pinMode(RelayPin, OUTPUT); pinMode(button, INPUT); digitalWrite(RelayPin, flag); Serial.println(""); WorkTime = SecToMillis(Work); SleepTime = SecToMillis(Sleep); PreviousMillis = millis(); } void loop() //************************************************************************** { while(true) { CurrentMillis = millis(); // ResetTimeToWork(); // milis() SwichFlag(); // SwichRelay(); // , ResidueTime(); // Button(); // tempo++; handOn = false; delay(100); } } //------------------------------------- ---------------------------------------------- void SwichFlag() { if(flag && CurrentMillis-PreviousMillis>=SleepTime) { PreviousMillis = CurrentMillis; flag = false; // , Serial.println("Flag On"); } else if(!flag && CurrentMillis-PreviousMillis>=WorkTime) //, , "" { PreviousMillis = CurrentMillis; flag = true; Serial.println("Flag OFF"); } } //------------------------------------- ------------------------------------------------------- void Button() { if(digitalRead(button)==HIGH) // { do { if(handOn) { delay(50); continue; } Serial.println("TURNED ON"); digitalWrite(RelayPin, LOW); // flag = true; handOn = true; delay(100); // }while (digitalRead(button)==HIGH); CurrentMillis = millis(); // PreviousMillis = CurrentMillis; // delay(20); } } //------------------------------------- --------------------------- unsigned long SecToMillis(unsigned long Temp) { return Temp*1000; } //------------------------------------- ---------------------------------------------- void ResidueTime() { if(CurrentMillis<PreviousMillis && tempo > iter) { if(flag) { TimeLeft = timeNextSwich/1000+1; Serial.print(" Time to ON: "); Serial.print(TimeLeft); Serial.print("sec"); Serial.println(""); } else { TimeLeft = timeNextSwich/1000+1; Serial.print(" Time to OFF: "); Serial.print(TimeLeft); Serial.print("sec"); Serial.println(""); } tempo = 0; } if(tempo > iter) // { if(flag) { TimeLeft = (PreviousMillis+SleepTime-CurrentMillis)/1000+1; Serial.print(" Time to ON: "); Serial.print(TimeLeft); Serial.print("sec"); Serial.println(""); } else { TimeLeft = (PreviousMillis+WorkTime-CurrentMillis)/1000+1; Serial.print(" Time to OFF: "); Serial.print(TimeLeft); Serial.print("sec"); Serial.println(""); } tempo = 0; } } //------------------------------------- milis(); void ResetTimeToWork() { while(CurrentMillis<PreviousMillis) // { if(flag) // { timeNextSwich = SleepTime-(4294967295-PreviousMillis); // while(timeNextSwich>=CurrentMillis) // { CurrentMillis = millis(); ResidueTime(); Button(); // , ResetTimeToWork()! if(CurrentMillis>PreviousMillis) return; tempo++; // ResidueTime(); } flag = false; PreviousMillis = CurrentMillis; // CurrentMillis = millis(); return; } if(!flag) { timeNextSwich = WorkTime-(4294967295-PreviousMillis); while(timeNextSwich>=CurrentMillis) // { CurrentMillis = millis(); ResidueTime(); Button(); if(CurrentMillis>PreviousMillis) return; tempo++; } flag = true; PreviousMillis = CurrentMillis; CurrentMillis = millis(); return; } } } //-------------------------------------- -------------------------------------------------- void SwichRelay() { if(!flag) { digitalWrite(RelayPin, flag); // } else { digitalWrite(RelayPin, flag); // } }
Sobre el código. El programa fue escrito en varios enfoques, modificando el proceso de identificación de deficiencias. Parece bastante confuso, pero intentaré aclararlo.
Funciona de la siguiente manera:
0) La arquitectura del programa está diseñada para interrogar a cualquier dispositivo externo (botón, sensor de presión, temporizador, etc.) y configurar la bandera para habilitar o deshabilitar el relé, y luego, usando una función separada, verificar el estado de la bandera y cambiarla a la posición adecuada.
1) El código del programa se basa en el temporizador de la función millis (), la función ResidueTime () calcula el tiempo de la próxima conmutación de relé, SwichRelay () verifica el estado de la bandera y da el comando de conmutación, si es necesario.
2) El relé se enciende cuando se aplica una señal baja desde el tramo PB7. Cuando se enciende el dispositivo, después de la inicialización del MK, el relé cambia a la posición de ENCENDIDO, suministrando voltaje a la bobina de arranque, y que a su vez suministra voltaje a la bomba.
3) El tiempo de funcionamiento del dispositivo es de 2 minutos, después de lo cual pasa al modo de espera durante 20 minutos.
4) El encendido del interruptor se procesa inmediatamente y, después de apagarlo, el programa mantiene un intervalo inactivo de 20 minutos. Esto es para asegurar que el pozo reponga el agua evacuada y para excluir el caso de hacer funcionar la bomba en seco.
5) Además, la función ResetTimeToWork () está presente en el código, que se activa cuando se desborda la función millis (), que
Devuelve el número de milisegundos desde el inicio de la ejecución del programa actual en la placa Arduino. Esta cantidad se restablece a cero, debido al desbordamiento del valor, después de aproximadamente 50 días.
(del sitio web Arduino.ru)
Por lo tanto, para que el dispositivo no "caiga" después de este período de funcionamiento continuo, se ha desarrollado la función mencionada que garantiza el funcionamiento estable del dispositivo sin reinicio adicional.
Procedemos a la recogida del circuito.
Esquema de montaje:

La señal del tramo PB4 debe presionarse al suelo con una resistencia de 4.7K ohmios, de lo contrario, el relé no funciona correctamente.
En la caja instalamos el dynrey para el iniciador:

Y montamos las partes restantes, arreglando su posición usando mocos calientes, como en la primera foto.

Se debe cortar un orificio para el arrancador en la tapa; es más alto que la profundidad de la caja.
No olvide instalar la fuente de alimentación para la placa, puede ocultarla dentro de la caja, todavía hay suficiente espacio en ella, o sacarla y enchufarla a la toma de corriente más cercana.
El dispositivo terminado, solo queda colocar un cable de 230V en los terminales del arrancador y conectar la carga.

El interruptor usó el viejo, se paró en la bomba. En el exterior tiene una contaminación irreparable por cemento y otras abrasiones, pero tiene un recinto sellado, por dentro está completamente intacto y continuará funcionando correctamente en el jardín durante mucho tiempo. Dada la escasa corriente de conmutación, casi para siempre, hasta que se rompe mecánicamente.
Gracias a
HWman por enviar un artículo sobre stm32 en el marco ARDUINO.
Adjunto el archivo con el boceto.