Skocz do zawartości

Modbus ESP32 - w jaki sposób odczytać tylko jeden bit rejestru?


Pomocna odpowiedź

Napisano (edytowany)

Witam !!

Obecnie odczytuję cały rejestr holdingowy

0x40000

zmienna1 = modbusTCPServer.holdingRegisterRead(0)

W jaki sposób odczytać tylko jeden bit tego rejestru ? 0 bit i 1 bit ?

0x40000.0

Pozdrawiam !

Edytowano przez robo1973
(edytowany)

W HMI Weintek tak to właśnie działa, dla sterownika SG2/3 TECO to 4x adres_rej.bit

Przykład monitorowania znacznika M32, który zmienia swój stan raz na sekundę. Tabela rejestrów, implementacja dla HMI Weintek.

SG2_adresowanie.thumb.jpg.34a668dadfa8bcb9517c35bef6bc6d92.jpg

Ale.... no właśnie. Dużo zależy od implementacji standardu MODBUS RTU w danym urządzeniu przez producenta. Tak naprawdę trzeba szukać dokumentacji dla danego urządzenia, ponieważ różni producenci różnie implementują standard (tzn. nie zawsze implementują go w 100%)

Edytowano przez BlackJack
(edytowany)

no tak Ale ja używam biblioteki Modbus do esp32

i chcę odczytać  0x40000.0  zerowy bit

zmienna1 = modbusTCPServer.holdingRegisterRead(0x00) >????

Edytowano przez robo1973
(edytowany)
11 minut temu, robo1973 napisał:

no tak Ale ja używam biblioteki Modbus do esp32

i chcę odczytać  0x40000.0  zerowy bit

zmienna1 = modbusTCPServer.holdingRegisterRead(0x00) >????

Myślę że metoda będzie ta sama, tylko ty musisz wpisać to w kodzie, a ja używam programu do panelu.

Z drugiej strony, skoro odczytujesz cały rejestr, to co za problem z niego wyłuskać sobie interesujący cię bit, za pomocą operacji AND. Jak masz już odczytany rejestr, to możesz sobie zrobić z tym co chcesz.

Edytowano przez BlackJack
(edytowany)

jeszcze raz spytam

Uruchomiłem serwer Modbus TCP na wt32 ETH01
odczytuję rejestr holdingowy przychodzący z klienta 16 bitów

int SET_PIN_krok_M = modbusTCPServer.holdingRegisterRead(0x00);

W jaki sposób odwołać się do poszczególnych bitów (odczytać wartość bitu 0, 1, 2 do 16 )
Pozdrawiam !!!

Edytowano przez robo1973

ok dzięki za pomoc ale na razie nic z tego nie kumam

odczytuję rejestr 16 bitowy zmienna1 = modbusTCPServer.holdingRegisterRead(0x00)

i co dalej ? Może jakiś początek..

Ok, żeby nie motać, 3 sposoby (pewnie jest ich więcej):

Struktura i wskaźnik, którym pokazujesz w "specyficzny" sposób na swoje 2-bajtowe dane z rejestru (cout, endl, "<<" służą tylko do wypisywania, nie zwracaj na to uwagi):

#include <iostream>
#include <cstdint>
using namespace std;

struct bajty_na_bity { 
	uint16_t _0: 1, _1: 1, _2: 1, _3: 1, _4: 1, _5: 1, _6: 1, _7: 1, _8: 1, _9: 1, _10: 1, _11: 1, _12: 1, _13: 1, _14: 1, _15: 1; 
} typedef bb; // to tylko alias nazwy, skrócony

int main() {
	uint16_t SET_PIN_krok_M = 0xABCD; // 0xABCD (dwa bajty) dla testu, u ciebie to dane z rejestru
	bb * wsk = reinterpret_cast<bb *>(&SET_PIN_krok_M);
	
	// wskaźnikiem odnosisz się do bitów w bajcie
	cout << "bit0: " << wsk ->_0 << endl; 
	cout << "bit1: " << wsk ->_1 << endl;
	cout << "bit2: " << wsk ->_2 << endl;
	cout << "bit3: " << wsk ->_3 << endl;

	return 0;
}

 

Sposób z unią i strukturą; do bitów odnosisz się podając np. ".bit._0"

#include <iostream>
#include <cstdint>
using namespace std;

union bity_na_bajty {
	struct { uint16_t _0: 1, _1: 1, _2: 1, _3: 1, _4: 1, _5: 1, _6: 1, _7: 1, _8: 1, _9: 1, _10: 1, _11: 1, _12: 1, _13: 1, _14: 1, _15: 1; } bit;
	uint16_t bajty;
} typedef bb; // to tylko alias nazwy, skrócony

int main(){
	bb SET_PIN_krok_M;
	SET_PIN_krok_M.bajty = 0xABCD; // 0xABCD (dwa bajty) dla testu, u ciebie to dane z rejestru
	
	// odnosisz się do bitów w bajcie
	cout << "bit0: " << SET_PIN_krok_M.bit._0 << endl;
	cout << "bit1: " << SET_PIN_krok_M.bit._1 << endl;
	cout << "bit2: " << SET_PIN_krok_M.bit._2 << endl;
	cout << "bit3: " << SET_PIN_krok_M.bit._3 << endl;
	// itd
	
	return 0;
}

 

Funkcja z operacjami bitowymi:

#include <iostream>
#include <cstdint>
using namespace std;

int zwroc_bit(uint16_t & rejestr, int8_t bit){
	if(bit < 0 || bit > 15) return -1; // błąd, poza zakresem
	return (rejestr >> bit) & 0x1;
}

int main(){
	uint16_t SET_PIN_krok_M = 0xABCD;
	
	cout << "bit0: " << zwroc_bit(SET_PIN_krok_M, 0) << endl;
	cout << "bit1: " << zwroc_bit(SET_PIN_krok_M, 1) << endl;
	cout << "bit2: " << zwroc_bit(SET_PIN_krok_M, 2) << endl;
	cout << "bit3: " << zwroc_bit(SET_PIN_krok_M, 3) << endl;
	
	return 0;
}

 

Wynik w każdym przypadku:

bit0: 1
bit1: 0
bit2: 1
bit3: 1

 

To samo widać w kalkulatorze, czytając cztery pierwsze bity od prawej (0) do lewej (15):

kalkulator.thumb.jpg.886c9d9b658fc2100a1df2cc95b43190.jpg

@robo1973 , kombinuj, coś wybierzesz.

Chociaż nie wiem, czy jest to po "arduinowemu", ale możesz też stworzyć prostą klasę z przeładowanymi operatorami i odnosić się do bitów rejestru łatwo, za pomocą indeksów. Sposób pewnie trochę przekombinowany i wymagający podstawowej wiedzy o klasach, ale działa. W użyciu skomplikowany nie jest.

#include <Arduino.h>

class bity{
	private:
		volatile uint16_t rejestr;
	public:
		bity() : rejestr(0) {}
		bity(uint16_t rej) : rejestr(rej) {}
		bity & operator = (uint16_t rej){
			rejestr = rej;
			return *this;
		}
		bity & operator += (int x){
			rejestr += x;
			return *this;
		}
		bity & operator -= (int x){
			rejestr -= x;
			return *this;
		}
		int operator [] (int idx) const {
			return (idx < 0 || idx > 15) ? -1 : (rejestr >> idx) & 0x1; // w razie przekroczenia zakresu (0-15) zwracane jest -1
		}
		operator uint16_t() const {
			return rejestr;
		}
};

void setup() {
	Serial.begin(9600);
	while(!Serial);
}

void loop() {
	static bity rejestr = 0xABCD; // tu twój rejestr

	Serial.printf("\n> Wartość rejestru (hex): 0x%4X\n", rejestr);

	// do bitów zmiennej "rejestr" odwołujesz się łatwo poprzez index, np. rejestr[0] to bit0
	// pamiętaj o zakresie 0-15 (czyli 16 bitów), inaczej funkcja zwróci błąd (-1)
	for(int i = 0; i <= 15; i++) Serial.printf("bit[%2i]: %i\n", i, rejestr[i]);

	// testowo, w każdym obiegu pętli, dodaję do rejestru 1:
	rejestr += 1;
	delay(5000);
}

 

Przykładowy wydruk:

> Wartość rejestru (hex): 0xABCD
bit[ 0]: 1
bit[ 1]: 0
bit[ 2]: 1
bit[ 3]: 1
bit[ 4]: 0
bit[ 5]: 0
bit[ 6]: 1
bit[ 7]: 1
bit[ 8]: 1
bit[ 9]: 1
bit[10]: 0
bit[11]: 1
bit[12]: 0
bit[13]: 1
bit[14]: 0
bit[15]: 1

> Wartość rejestru (hex): 0xABCE
bit[ 0]: 0
bit[ 1]: 1
bit[ 2]: 1
bit[ 3]: 1
bit[ 4]: 0
bit[ 5]: 0
bit[ 6]: 1
bit[ 7]: 1
bit[ 8]: 1
bit[ 9]: 1
bit[10]: 0
bit[11]: 1
bit[12]: 0
bit[13]: 1
bit[14]: 0
bit[15]: 1

 

Wszystko działa !! Dziękuję

Chciałbym jeszcze jakoś fajnie zrobić zapisywanie do rejestru modbusTCPServer.inputRegisterWrite(0x00, 0x01);

poszczególnych bitów . Teraz załączam bit najmłodszy .

W zależności od warunku albo podając numery bitów chcę je włączać

Pozdrawiam !

 

@robo1973 , dokończyłem, nawet działa, ale zapomnij o tym. Człowiek czasem <gupi> i walczy jak Don Kichot z wiatrakami, a wystarczyło spojrzeć tu (sekcja: "bity & bajty"): https://www.arduino.cc/reference/pl/

Przykładowo:

void setup() {
	Serial.begin(9600);
	while(!Serial);
}

void loop() {
	uint16_t rejestr = 0xABCD;
	Serial.printf("rejestr przed zmianą: 0x%4X (bit0: %i)\n", rejestr, bitRead(rejestr, 0));

	bitClear(rejestr, 0); // ustawia bit0 na 0
	Serial.printf("rejestr po zmianie: 0x%4X (bit0: %i)\n\n", rejestr, bitRead(rejestr, 0));

	delay(5000);
}

 

Jest też biblioteka standardowa jeżeli arduinów będzie za mało: https://en.cppreference.com/w/cpp/utility/bitset

  • 2 tygodnie później...
(edytowany)

Witam !!!

Z Modbus otrzymuję  bit_0 = zwroc_bit(SET_PIN_krok_M, 0)

Chciałbym teraz żeby ten bit wygenerował mi przebieg prostokątny o czasie trwania np 500 ms.

Czyli w chwili gdy pojawia się zbocze narastające (zamiana stanu z 0 n na 1 na bit_0 ) program wygeneruje prostokąt.

Kolejne generowanie prostokąta nastąpi po ponownym pojawianiu się zbocza narastającego na bit_0

Trzeba pewnie odczytywać zbocze narastające na bit_0

Czy jest do tego gotowa funkcja Myślałem o przerwaniach ale one tylko na fizyczne wejścia działają ?

Proszę o pomoc  i dziękuję pozdrawiam !! >

Edytowano przez robo1973

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...