Mam tu małą zagwozdkę, której nie potrafię sensownie wytłumaczyć. Otóż aplikacja działa i działa prawidłowo jeśli urządzenie zostanie uruchomione przez załączenie napięcia zasilania sieciowego (Układ posiada mały impulsowy zasilacz AC/DC dostarczający 12V oraz step-down dostarczający potem 5V). Oba czujniki zostaną wtedy znalezione na magistrali, ich adresy wpisane do DS18B20_ID_Table i z obu temperatura jest prawidłowo czytana.
Jednak przy opracowywaniu programu, gdy urządzenie ma zasilanie i zostanie ponownie zaprogramowane - z wprowadzeniem procesora w stan RESET na czas programowania, nagle jeden z czujników nie zwraca temperatury i nie można go zaadresować. Muszę urządzenie odłączyć od zasilania i włączyć ponownie.
Co dziwne, odkryłem iż w takim przypadku - czyli startu od RESETu - pierwszy czujnik "przesunie się" w tabeli DS18B20_ID_Table na drugą pozycję, drugi zaś będzie na pozycji trzeciej. Gdy zmodyfikuję kod, by korzystał z takiego ułożenia adresów czujników w tabeli to aplikacja będzie odczytywać czujniki poprawnie.
Takie zachowanie układu stawia pod znakiem zapytania uruchomienie systemu Watchdog. Gdyby doszło do resetu procesora w wyniku zawieszenia aplikacji układ nagle przestanie czytać jeden z czujników, a to byłoby niedopuszczalne.
Najistotniejszy fragment kodu z pliku "main.h" poniżej. W plikach "one_wire.h"/"one_wire.c" są procedury związane z realizacją magistrali 1-Wire przy wykorzystaniem dostępnego UARTu. Są to procedury zaczerpnięte z książki Tomka Francuza, przeportowane z AVR do STM8 i korzystają z kilku funkcji biblioteki SPL dla układów STM8.
Code: Select all
#include "one_wire.h"
#include <string.h>
/*****************************************************************************/
/* Zmienne globalne */
/*****************************************************************************/
/**
* @brief Zmienne przechowujące struktury danych z czujników DS18B20
*/
uint8_t DS18B20_ID_Current[8]; /* Bieżące ID czujnika w trakcie wyszukiwania */
uint8_t DS18B20_ID_Table[MAX_DS18B20_ID][7];
/* Tabela ID wykrytych czujników na magistrali */
int16_t DS18B20_RetValue; /* Wartość zwracana przez zaadresowany czujnik */
uint8_t DS18B20_Found; /* Liczba odnalezionych czujników */
uint8_t DS18B20_BitDiff = 0; /* Numer bitu różniącego się przy wyszukiwaniu */
/*****************************************************************************/
/* Funkcje konfiguracji */
/*****************************************************************************/
/**
* @brief Konfiguracja portów GPIO
* @param Brak
* @retval Brak
*/
static void STM8_GPIO_Setup(void)
{
(...)
/* Piny UART */
GPIO_Init(UART_PORT, TX_PIN, GPIO_MODE_OUT_PP_HIGH_FAST);
GPIO_Init(UART_PORT, RX_PIN, GPIO_MODE_IN_FL_NO_IT);
(...)
}
/*****************************************************************************/
/* Funkcje obsługi DS18B20 - by Tomasz Francuz */
/*****************************************************************************/
/**
* @brief Funkcja rozpoczynająca konwersję temperatury przez wszystkie
* układy DS18B20
* @param block : Wartość 0 wyłącza blokadę działania programu na
* czas konwersji. Wartość 1 włącza blokadę.
* @retval Brak
*/
static void DS18B20_Start_Conversion(uint8_t block)
{
/* Czy coś jest na magistrali */
if(OW_WaitForPresencePulse() == 0) return;
/* Jeśli tak to pomijamy polecenie MATCH ROM i wysyłamy od razu CONVERT T */
OW_Write(OW_SKIPROM);
OW_Write(OW_CONVERT);
/* Czy czekamy na odpowiedź? */
if(block) while(!OW_ReadBit());
}
/**
* @brief Funkcja odczytująca temperaturę z pamięci wybranego
* układu DS18B20
* @param aID : Wskaźnik na tablicę z numerem seryjnym
* adresowanego czujnika
* @retval Funkcja zwraca 16 bitową wartość temperatury
*/
static int16_t DS18B20_GetTemperature(uint8_t *aID)
{
uint16_t temp;
/* Adresujemy urządzenie i sprawdzamy czy odpowiada */
OW_SelectDevice(aID);
if(OW_GetError() != OW_OK) return 0xFFFF;
/* Czytamy zawartość pamięci czujnika i przeliczamy */
OW_Write(OW_READ_SCRATCHPAD);
temp = OW_Read();
temp = temp + (OW_Read() << 8);
/* Konwersja kodów - tylko wartości całkowite */
if(temp & 0x8000) temp = 1 - (temp ^ 0xFFFF);
return temp;
}
/*****************************************************************************/
/* Funkcje głównego programu */
/*****************************************************************************/
/**
* @brief Funkcja inicjalizacyjna programu
* @param Brak
* @retval Kod wyjścia - Brak
*/
static void SystemInit(void)
{
STM8_Clock_Setup();
STM8_GPIO_Setup();
STM8_TIM4_Setup();
STM8_TIM2_Setup();
enableInterrupts();
OW_Init();
(...)
/* Skanuj magistralę w poszukiwaniu czujników */
for(DS18B20_Found = 0; DS18B20_Found < MAX_DS18B20_ID; DS18B20_Found++) {
DelayMs(100);
OW_SetError(OW_OK);
/* Przeszukaj magistralę w poszukiwaniu unikalnych ID */
DS18B20_BitDiff = OW_Search(OW_SEARCHROM, DS18B20_ID_Current, DS18B20_BitDiff);
if(OW_GetError() != OW_OK) break;
/* Skopiuj zeskanowane ID do tabeli czujników */
memcpy(&DS18B20_ID_Table[DS18B20_Found][0], DS18B20_ID_Current, 7);
/* Jeśli nie ma już unikalnych ID to opuść pętlę */
if(DS18B20_BitDiff == 0) break;
}
/* Rozpocznij konwersję temperatury wszystkich czujników i zaczekaj na wynik */
DS18B20_Start_Conversion(1);
for(uint8_t idx = 0; idx <= DS18B20_Found; idx++) {
/* Odpytaj kolejno każdy czujnik z ID_Table i wprowadź dane do systemu */
DS18B20_RetValue = DS18B20_GetTemperature(&DS18B20_ID_Table[idx][0]);
switch(idx) {
case 0: Temperature.actual_t1 = (DS18B20_RetValue / 16); break;
case 1: Temperature.actual_t2 = (DS18B20_RetValue / 16); break;
default: break;
}
}
(...)
}
/*****************************************************************************/
/* Funkcja main programu */
/*****************************************************************************/
/**
* @brief Główna funkcja programu
* @param Brak
* @retval Kod wyjścia - Brak
*/
int main(void)
{
SystemInit();
while(1) {
/* Rozpocznij konwersję temperatury wszystkich czujników i zaczekaj na wynik */
DS18B20_Start_Conversion(1);
DelayMs(200);
for(uint8_t idx = 0; idx <= DS18B20_Found; idx++) {
/* Odpytaj kolejno każdy czujnik z ID_Table i wprowadź dane do systemu */
DS18B20_RetValue = DS18B20_GetTemperature(&DS18B20_ID_Table[idx][0]);
switch(idx) {
case 0: Temperature.actual_t1 = (DS18B20_RetValue / 16); break;
case 1: Temperature.actual_t2 = (DS18B20_RetValue / 16); break;
default: break;
}
}
(...)
}
Tu udało mi się uchwycić co się dzieje na magistrali po załączeniu zasilania. Z prawdopodobnym wskazaniem miejsc w kodzie.
A tu dziwne przebiegi po RESET. Nie rozpoznaję co tu się dzieje w stosunku do kodu. Prawdopodobnie źle to jest uchwycone.