Continuo a série de artigos sobre construção de bicicletas no campo do gerenciamento de circuitos de baixa tensão. Desta vez, falarei sobre um dispositivo que impede a descarga profunda de uma bateria de carro por vários consumidores secundários.
Uma das possíveis conseqüências de uma descarga não controlada.Comprar o primeiro carro ou moto é um marco significativo na vida de todas as pessoas, especialmente de um engenheiro. Afinal, quem mais além das vantagens óbvias de seu novo cavalo de ferro presta atenção imediatamente às suas desvantagens não óbvias? Quem imediatamente começa a pensar em quaisquer melhorias e acréscimos ao padrão? Obviamente, se este é um carro do segmento superior e até uma marca "na moda", a princípio pode parecer que ele tem absolutamente tudo. Mas, como mostra a prática, neste caso, o tempo refuta as primeiras impressões. Se você compra um carro de classe econômica, suas mãos começam a coçar literalmente no primeiro dia!
O desejo de "encher" seu carro com vários dispositivos eletrônicos auxiliares é bastante natural. No entanto, logo após a implementação de todos esses planos, a vida confronta o proprietário do carro com uma dura realidade. Acontece que mesmo os dispositivos mais modernos construídos na base elementar mais recente ainda estão bastante ansiosos por eletricidade. E uma bateria de carro que parece tão grande não é um reator nuclear e pode facilmente "sentar-se" sob o peso de todos esses consumidores aparentemente inofensivos em questão de dias.
Para não avançar ainda mais em situações abstratas e hipotéticas, irei direto à minha história. Depois de comprar um carro, o primeiro foi o desejo de colocar um registrador nele. Isso foi feito no menor tempo possível, quase completamente ditado pela velocidade de entrega do pacote no AliExpress. É claro que a fonte de alimentação regular do isqueiro era extremamente inconveniente, e o gravador rapidamente conseguiu uma conexão estacionária à linha mais próxima da rede de bordo por meio de um conversor de pulso de 12 / 5v. E desde foi, para dizer o mínimo, não ontem, esse conversor não era nem moderno, para suas próprias necessidades, como se viu mais tarde, estava consumindo até 21 mA de corrente. Agora vamos estimar quanto esse conversor poderia alimentar apenas uma bateria nova e totalmente carregada, com uma capacidade de 60 Ah. A aritmética é extremamente simples e decepcionante.

Assim, em menos de quatro meses, um conversor que não esteja carregado com nada aterrará a bateria literalmente "a zero". Se levarmos em conta que uma bateria que não é totalmente nova pode facilmente ficar viúva e a carga após a cidade pokatushki está longe de 100%, um dia chuvoso começa facilmente dentro de um mês com um gancho.
E isso é tudo, repito, apenas um conversor de tensão. Sim, hoje você pode comprar um conversor que leva apenas meio miliampere para suas próprias necessidades, mas eu dei este exemplo apenas para mostrar com que lentidão e confiança a
água afia uma pedra, mesmo que insignificante, mas constantemente atuando, o consumidor consome energia do que parece ser tão grande bateria.
Vamos além: o gravador no modo de gravação FHD a 30fps consome quase 300 mA da fonte + 5v, que após a conversão, levando em consideração a eficiência, fornece cerca de 150 mA de corrente da rede de bordo. Suponha que o conversor seja substituído por um conversor moderno e calculemos o tempo de descarga somente com essa corrente.
Pouco mais de duas semanas, mas na prática - dez dias. Agora, a perspectiva de iluminação (e possivelmente a troca da bateria) está se aproximando após as próximas férias ou viagem de negócios.
E assim aconteceu comigo: quando saí de férias curtas e forçadas, não pensei que em uma semana mais ou menos uma fechadura central não pudesse abrir a porta para mim.
Muitos dirão que a culpa é deles, que tudo deve ser desenergizado, ou pelo menos parar de gravar, e eles estarão certos. Mas a vida é vida, e a memória não é a mesma, e quanto tempo dura a folga por doença nem sempre é possível saber com antecedência. Portanto, a idéia de um disjuntor surgiu imediatamente.
É claro que existe uma opção para ligar o gravador a partir do interruptor de ignição, para que ele funcione apenas em movimento, mas essa opção também não é muito, porque se o carro bater no estacionamento, eu gostaria de ter a chance de ver o culpado. Além disso, após um curto período de tempo após a instalação do gravador, o carro estava com poucos dispositivos, incluindo um rastreador GPS oculto, que deveria funcionar, se não até o fim, pelo menos até quando "quase tudo" já estivesse lá.
Em geral, durante várias semanas de reflexão passiva, a idéia de um dispositivo que deve controlar a tensão da rede de bordo e com base nesses dados para controlar a fonte de alimentação de dois grupos de consumidores: secundário (gravador, soquete USB) e básico (rastreador GPS e alguns o que).
Como isso pôde ser feito
Os primeiros protótipos virtuais do dispositivo foram "construídos" com base nos comparadores analógicos LM393N e conseguiram tudo o que foi originalmente planejado para ser recebido do dispositivo. O esquema abstrato era algo assim.
Aqui, dois comparadores são usados para alternar cargas. Um gerador de tensão de referência comum, dois divisores que determinam os limites de operação, comparadores de cintas, dois interruptores de energia. A ligação externa do dispositivo acabado é planejada da seguinte maneira.
A chave primária permanece ativada por mais tempo que a secundária, portanto, o próprio conversor abaixador é alimentado por ela. As cargas primárias são conectadas diretamente ao conversor. O interruptor secundário comuta as cargas secundárias já no circuito + 5v na saída do inversor.
O que saiu no final
Parece ser tudo o que é necessário, mas, como costuma acontecer, com o pensamento dos detalhes, surgiram idéias de implementações alternativas. Em primeiro lugar, o circuito analógico continha uma montanha decente de elementos discretos que fornecem modos de operação do comparador e, em segundo lugar, os limites de trip devem ser definidos usando resistores de compensação, o que complica a configuração e cria a probabilidade de "fugir" dos solavancos e do tempo. Portanto, no final, optou-se por uma implementação digital, que acabou sendo muito mais simples, tanto esquematicamente quanto em configuração, ao mesmo tempo em que abriu enormes oportunidades para melhorar o algoritmo de controle e, mais importante, nesse contexto, tornou-se uma ordem de magnitude mais econômica em termos de consumo atual.
O controlador ATtiny13A simplesmente solicitou o coração do dispositivo, que, além da facilidade de uso e baixo custo, ainda está disponível em uma caixa DIP de tubo quente e quente para oldfag. Inicialmente, os recursos de um controlador tão pequeno pareciam redundantes em todas as frentes, desde o número de entradas / saídas até a quantidade de programa e RAM, no entanto, como você sabe, o apetite vem com uma refeição. Como resultado, olhando para o futuro, direi que a versão final do caso acabou sendo todas as conclusões do microcircuito, e a memória do software livre não deixou mais do que duas dúzias de bytes.
Para medir a tensão da rede de bordo, o microcontrolador exigiu apenas uma entrada, que está vinculada ao ADC. Mais duas saídas lógicas foram gerenciar os consumidores. Antes de tudo, após a transição mental final para o "digital", havia o desejo de adaptar dois GPIOs gratuitos aos negócios, e a decisão não demorou a chegar. Quando, mais uma vez, no frio, o motor de partida ligou o motor com uma lágrima mal oculta, a presença de um sensor de temperatura no circuito e no algoritmo parecia muito útil. Como resultado, o segundo ADC foi usado para medir a temperatura. E, para que o termistor consuma corrente somente quando necessário, foi decidido alimentá-lo a partir da última saída lógica restante.
Como resultado, o diagrama do dispositivo adquiriu uma forma final.
Aqui vemos o mínimo de detalhes e, entre eles, nada está sujeito a nenhum tipo de "distorção". Vamos examinar brevemente os pontos principais.
Para a fonte de alimentação, o controlador precisa de uma tensão estável de 1,8 a 5,5 V, o que significa que deve haver um estabilizador no circuito que diminua a tensão da rede de bordo para o nível necessário. Do ponto de vista da economia de energia, pode parecer que existe um local para um conversor de redução de pulso exclusivamente, mas isso é apenas à primeira vista. O fato é que o ATtiny13A, mesmo no modo de operação com maior consumo de energia (frequência 8 MHz, execução de código ativo), consome não mais que 6 mA. Nesse esquema, o controlador 99% do tempo está no modo de sono profundo e também opera a uma frequência de 1,2 MHz, resultando em um consumo médio de aproximadamente menos de 15 µA. Além disso, aproximadamente 80 µA às correntes de base dos transistores de controle (se as duas cargas estiverem ativadas). Bem, por uma pequena fração de segundo, a energia do termistor é ativada, o que adiciona cerca de 25 microamperes à corrente média. E aqui está a resposta para a pergunta "vale a pena carregar um conversor de pulsos por uma carga com um consumo não superior a 120 µA?" Não parece tão simples. E se considerarmos que estamos lidando com medições analógicas, definitivamente não vale a pena. Portanto, o estabilizador linear LP2950 foi usado, um análogo funcional do popular 78L05, mas muito mais econômico. Este conversor pode fornecer até 100 mA de corrente na saída, enquanto consome não mais que 75 µA para o ente querido.
O divisor de tensão da rede de bordo, protegido por um diodo zener e um capacitor, permite medir tensões de até 15 V.
Sei que agora uma onda de críticas me impressionará por essa decisão, mas seremos objetivos. Em primeiro lugar, não estou desenvolvendo um satélite e, em segundo lugar, não existe um fator único que leve ao desastre. A resistência do ombro é alta, o diodo zener é capaz de desviar muito mais corrente do que aquela que pode fluir através do divisor, mesmo no cenário mais pessimista. Dos pulsos de alta frequência, quando o diodo zener não tem velocidade suficiente, o capacitor C2 protege (com um resistor R7, ele cria um filtro passa-baixo com uma frequência de corte de apenas 7 Hz). D1 e R6, em certa medida, asseguram que o esquema não caia. E não se deve esquecer a linearidade, qualquer método de isolamento galvânico em tal local tornará o cálculo teórico dos valores completamente irrealista, teremos que calibrar pelo menos o protótipo, mas não precisamos dele.
A resistência de saída do divisor é dez vezes maior que os 10 kOhm recomendados para a fonte de sinal ADC, mas, graças ao capacitor C2, não há problemas de medição.
Em geral, a impedância de entrada dos circuitos ADC dos controladores AVR de acordo com a folha de dados é declarada em pelo menos 100 megaegohms. No entanto, a mesma folha de dados recomenda o uso de fontes com resistência interna de até 10 kOhm. Porque O ponto é o princípio de operação deste próprio ADC. O conversor opera com o princípio da aproximação sequencial e seu circuito de entrada é um filtro passa-baixo de um resistor e capacitor. A obtenção de uma amostra de 10 bits é iterativa e é necessário que o capacitor seja carregado com toda a tensão medida durante todo o tempo de medição. Se a impedância de saída da fonte for muito grande, o capacitor continuará sendo carregado diretamente durante o processo de conversão e o resultado será impreciso. No nosso caso, a capacitância C2 é mais de sete mil vezes a capacidade do filtro ADC, o que significa que quando a carga é redistribuída entre esses capacitores quando eles são ligados no momento da medição, a tensão de entrada diminui em não mais que 1/7000, o que é sete vezes menor que a precisão máxima de um ADC de 10 bits. É verdade que você precisa ter em mente que esse truque funciona apenas para medições únicas com pausas significativas entre elas; portanto, não deve "melhorar" o programa de controle adicionando um ciclo a ele para várias medições consecutivas com a média do resultado.
O divisor com um termistor devido à presença de uma fonte de energia controlada é construído usando as classificações recomendadas. O NTCLE100E3 é usado como sensor, mas não há restrições, você pode usar qualquer termistor com aproximadamente a mesma classificação, o principal é fazer correções correspondentes à sua característica nas constantes do código fonte, para que a tensão do divisor seja convertida no valor correto de temperatura.
Como teclas de controle, MOSFETs de canal P de qualquer tipo são usados com uma resistência de canal aberto aceitável e uma tensão máxima de fonte de dreno de pelo menos 30 volts. O circuito acima usa diferentes transistores. Isso é feito porque eles precisam alternar tensões diferentes e o tipo de cada uma delas foi selecionado para condições de trabalho específicas. O transistor superior deve ter mais alta voltagem e o menor, se possível, ter uma resistência mínima de canal aberto. Mas, repito, essa decisão é ditada pelo circuito de comutação do dispositivo (veja acima), com outra inclusão os requisitos para o transistor inferior podem ser diferentes.
Para controlar os interruptores de energia, é usado um par de transistores bipolares idênticos. A princípio, pode parecer que esses transistores sejam supérfluos, mas aqui não é tão simples. Os transistores de efeito de campo com uma porta isolada começam a abrir não a partir de qualquer voltagem da polaridade necessária na porta, mas somente após atingir um certo nível de limite, que aparece nas folhas de dados sob o nome "tensão limite de porta a fonte" e geralmente é igual a 2..4 V. Agora vamos apenas conte. O circuito de saída do controlador pode formar dois níveis lógicos: "0" lógico com tensão tendendo a zero; e “1” lógico com tensão tendendo a fornecer. Quando alimentados por 5 volts, serão tensões de cerca de 0 e 5 V, respectivamente. Como resultado, ao alternar uma fonte de 12 volts, um “0” lógico no portão criará uma diferença de tensão no portão da fonte 12 - 0 = 12 volts, o transistor de potência está aberto. Tudo parece estar normal, mas o lógico "1" com sua voltagem de 5 V criará uma voltagem entre 12 - 5 = 7 volts entre a fonte e a porta, e o transistor de energia ainda permanecerá aberto. Assim, o sinal de controle de cinco volts não pode controlar a tecla, que alterna a tensão acima de 7..9 volts. Portanto, os transistores bipolares de controle não funcionam tanto com teclas de sinal quanto com amplificadores que aumentam a tensão de controle de 5 volts para a tensão da rede de bordo.
O resistor no circuito base de cada um dos transistores de controle limita simplesmente a corrente das saídas do controlador a um nível suficiente para controlá-lo. Suas classificações podem ser reduzidas duas a três vezes, sem consequências para a operação do circuito.
É fácil ver que os transistores de controle não estavam no circuito analógico baseado no LM393N. O fato é que o estágio de saída do comparador selecionado é construído de acordo com o circuito coletor aberto, ou seja, sua saída é simplesmente a saída do coletor de transistor terminal. Esse princípio de construção exige que peças adicionais sejam penduradas no chip para criar a carga do estágio de saída, mas, por outro lado, torna o chip muito flexível. Um coletor aberto permite que o comparador controle qualquer fonte de corrente aceitável, e não apenas compatível com a que fornece energia ao próprio comparador.
Devo dizer que limitar a tensão de limiar de um MOSFET de potência funciona não apenas para altas tensões, como mencionado acima, mas também para baixas. Afinal, se a tensão mínima de abertura do transistor for, digamos, 4 volts, ao trocar a fonte de 3,3 V, mesmo conectar a porta ao terra não criará a diferença de tensão desejada entre a fonte e a porta e o transistor permanecerá fechado. Portanto, 5 volts é, talvez, a tensão mínima que pode ser comutada com segurança pelos transistores selecionados.
Personalização
A configuração de um dispositivo é uma conversa separada. Por um lado, não há um único elemento de ajuste no circuito, mas, por outro lado, estamos lidando com medições de tensões com uma precisão não inferior a 0,1 V. Como conectar tudo isso? Existem duas maneiras. O primeiro é usar os resistores R6, R7 e R8 com uma tolerância de pelo menos 1% (ou melhor, 0,1%). O segundo envolve o uso de resistores convencionais com a medição de suas resistências reais e a correção de coeficientes no código fonte do programa.
O primeiro método é bom para a produção em massa, mas é muito mais atraente para nós não nos preocuparmos com a busca pelos valores de alta precisão necessários, então vamos pelo segundo caminho. A resistência pode ser medida com um multímetro comum, sua precisão aqui é suficiente. Outro objeto de medição será a tensão do estabilizador que alimenta o circuito. O ADC do controlador pode funcionar em modos diferentes, mas por várias razões, é mais conveniente usarmos aquele em que o resultado da conversão digital seja contado em relação à tensão de alimentação. É por isso que é importante conhecê-lo com a maior precisão possível.
O cálculo é extremamente simples e consiste em calcular o coeficiente de divisão do divisor resistivo e a proporção da conversão do resultado em LSB durante a conversão analógica para digital.
Ux é a tensão de entrada do divisor;
Ru é a resistência do braço do divisor (ao qual Ux é fornecido);
Rd é a resistência do braço inferior do divisor (que está conectado ao chão);
Uref - tensão de referência do ADC (ou seja, tensão de alimentação do controlador);
1024 - o número de valores discretos na saída de um ADC de 10 bits;
LSB é o valor numérico obtido pelo programa do ADC.
Vamos começar com o divisor de tensão R6-R7. . 5.0 . 13.5 :
, , , .
, , , Ru, Ux Uref. :
R8 , R9 NTCLE100E3 0⁰C:
, R8 R9 , , , . . , R9 , 0.5 m, . , , 0.01 .
, , , . , . - , .
, , , .
Firmware
AtmelStudio ( gcc-avr 5.4.0)
,
hex . , .
//#define F_CPU 1200000UL //
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <util/delay.h>
//#define DBG
#define TEMPERATURE_OVERHEAT 753 // LSB- +50⁰C
#define TEMPERATURE_GIST 8 // ( LSB)
#define VOLTAGE_GIST 3 // ( LSB)
#define INTERVAL WDTO_1S // (1 )
#ifndef DBG
#define CELL_CHANGE_TIMEOUT 90 // ( INTERVAL, 254)
#define OVERHEAT_TIMEOUT 300 // "" ( INTERVAL)
#else
#define CELL_CHANGE_TIMEOUT 2
#define OVERHEAT_TIMEOUT 3
#endif
typedef unsigned char bool; //
#define true 0 == 0 //
#define false 0 != 0 //
typedef enum {st_none = 0b00, st_primary = 0b01, st_secondary = 0b10, st_both = 0b11} t_states; //
// ,
typedef enum {adc_temperature, adc_voltage} t_measure; //
typedef enum {move_null, move_up, move_down} t_movement; //
//
struct t_coordidates {
signed char row, col;
};
//
struct t_correction {
t_movement voltage, temperature;
};
#define CELLS_ROWS 3 // ( )
#define CELLS_COLS 5 // ( )
//
const t_states CELLS[CELLS_ROWS][CELLS_COLS] = {
{st_both, st_both, st_both, st_primary, st_none},
{st_both, st_both, st_primary, st_none, st_none},
{st_both, st_primary, st_none, st_none, st_none}
};
// LSB- ,
const unsigned int ROWS_EDGES[CELLS_ROWS - 1] = {
241, // 0⁰C
157 // -10⁰C
};
// LSB- ,
const unsigned int COLS_EDGES[CELLS_COLS - 1] = {
864, // 13.5V
800, // 12.5V
787, // 12.3V
768 // 12.0V
};
unsigned int overheat_rest_time = 0; // ""
unsigned char cell_change_time = 0; //
unsigned char no_cur_cell_time = 0; // ,
#define NULL_CELL (struct t_coordidates){.col = -1, .row = -1} // ,
#define NULL_CORRECTION (struct t_correction){.voltage = move_null, .temperature = move_null} // ,
struct t_correction moved_from = NULL_CORRECTION; //
struct t_coordidates cur_cell = NULL_CELL, //
next_cell = NULL_CELL; // -
//
static void init_pins() {
DDRB |= (1 << PB0) | (1 << PB1) | (1 << PB3); // 2 (PB3), 5 (PB0) 6 (PB1)
PORTB &= ~(1 << PB0) & ~(1 << PB1) & ~(1 << PB3); // 2 (PB3), 5 (PB0) 6 (PB1)
}
// /
static void toggle_thermal_sensor(bool state) {
if(state) {
PORTB |= (1 << PB1); // state , 6 (PB1)
_delay_ms(5); //
} else {
PORTB &= ~(1 << PB1); // state , 6 (PB1)
}
}
//
static unsigned int measure_adc(t_measure measure) {
if(measure == adc_temperature) {
toggle_thermal_sensor(true); // ,
ADMUX = 0b10; // - 3 (PB4)
} else {
ADMUX = 0b01; // - 7 (PB2)
}
ADCSRA = (1 << ADPS2) | // = 16 (75 )
(1 << ADIE) | //
(1 << ADEN); //
set_sleep_mode(SLEEP_MODE_ADC); // ""
do {
sleep_cpu(); // , ,
} while(ADCSRA & (1 << ADSC)); // ,
ADCSRA = 0; //
toggle_thermal_sensor(false); //
return ADC; // 10-
}
// watchdog
static void init_interrupts(void) {
sleep_enable(); //
WDTCR = (1 << WDCE) | (1 << WDE); // watchdog
WDTCR = (1 << WDTIE) | INTERVAL; // watchdog , 1
sei(); //
}
//
static void toggle_loads(t_states states) {
unsigned char port = PORTB & ~((1 << PB3) | (1 << PB0)), // ,
bits = (((states & st_primary) >> 0) << PB3) | //
(((states & st_secondary) >> 1) << PB0);
PORTB = port | bits; //
}
// t_coordidates
static bool cells_equal(struct t_coordidates cell1, struct t_coordidates cell2) {
return cell1.row == cell2.row && cell1.col == cell2.col;
}
// LSB-
static signed char get_cell_row(unsigned int temperature) {
signed char row = 0;
while(row < CELLS_ROWS - 1) { //
if(temperature >= ROWS_EDGES[row]) { // temperature ,
return row;
} else {
++row;
}
}
return CELLS_ROWS - 1; // temperature ,
}
// LSB-
static signed char get_cell_col(unsigned int voltage) {
signed char col = 0;
while(col < CELLS_COLS - 1) { //
if(voltage >= COLS_EDGES[col]) { // voltage ,
return col;
} else {
++col;
}
}
return CELLS_COLS - 1; // voltage ,
}
// ,
static void get_row_edges(signed char row, unsigned int *upper, unsigned int *lower) {
*upper = row > 0 ? ROWS_EDGES[row - 1] : 0xffff - TEMPERATURE_GIST; // ,
*lower = row < CELLS_ROWS - 1 ? ROWS_EDGES[row] : TEMPERATURE_GIST; // ,
}
// ,
static void get_col_edges(signed char col, unsigned int *upper, unsigned int *lower) {
*upper = col > 0 ? COLS_EDGES[col - 1] : 0xffff - VOLTAGE_GIST; // ( ) ,
*lower = col < CELLS_COLS - 1 ? COLS_EDGES[col] : VOLTAGE_GIST; // ( ) ,
}
// -
static void gisteresis_correction(struct t_coordidates* new_cell, unsigned int temperature, unsigned int voltage) {
unsigned int upper_edge, lower_edge;
get_row_edges(cur_cell.row, &upper_edge, &lower_edge); //
if(new_cell->row > cur_cell.row && moved_from.temperature == move_up && temperature >= lower_edge - TEMPERATURE_GIST) {
--new_cell->row; // - , , ,
}
if(new_cell->row < cur_cell.row && moved_from.temperature == move_down && temperature <= upper_edge + TEMPERATURE_GIST) {
++new_cell->row; // - , , ,
}
get_col_edges(cur_cell.col, &upper_edge, &lower_edge); //
if(new_cell->col > cur_cell.col && moved_from.voltage == move_up && voltage >= lower_edge - VOLTAGE_GIST) {
--new_cell->col; // - , ( ), ,
}
if(new_cell->col < cur_cell.col && moved_from.voltage == move_down && voltage <= upper_edge + VOLTAGE_GIST) {
++new_cell->col; // - , ( ), ,
}
}
// stdlib::abs()
static unsigned char absolute(signed char value) {
return value >= 0 ? value : -value;
}
// -
static void calc_movement(struct t_coordidates new_cell) {
moved_from = NULL_CORRECTION; // -
if(!cells_equal(new_cell, NULL_CELL) && !cells_equal(cur_cell, NULL_CELL)) { // , -
if(absolute(new_cell.row - cur_cell.row) == 1) { //
moved_from.temperature = new_cell.row < cur_cell.row ? move_up : move_down; //
}
if(absolute(new_cell.col - cur_cell.col) == 1) { //
moved_from.voltage = new_cell.col < cur_cell.col ? move_up : move_down; //
}
}
}
// -
static void set_next_cell(struct t_coordidates cell) {
next_cell = cell;
cell_change_time = 0; //
}
//
static void set_cur_cell(struct t_coordidates cell) {
cur_cell = cell;
no_cur_cell_time = 0; //
set_next_cell(NULL_CELL); // -
}
// ,
static void change_cell(struct t_coordidates new_cell) {
if(cells_equal(new_cell, NULL_CELL)) { //
toggle_loads(st_none);
} else {
toggle_loads(CELLS[new_cell.row][new_cell.col]); //
}
calc_movement(new_cell); //
set_cur_cell(new_cell); //
}
//
static void main_proc(void) {
unsigned int temperature, voltage; // 10- LSB-
struct t_coordidates cell; // -
if(overheat_rest_time) { // "" ,
--overheat_rest_time;
} else {
temperature = measure_adc(adc_temperature); //
if(temperature >= TEMPERATURE_OVERHEAT) { // +50C, :
change_cell(NULL_CELL); // ( )
overheat_rest_time = OVERHEAT_TIMEOUT; //
} else {
voltage = measure_adc(adc_voltage); //
cell.col = get_cell_col(voltage); // -
cell.row = get_cell_row(temperature); // -
if(cells_equal(cur_cell, NULL_CELL)) { // ,
change_cell(cell);
} else {
gisteresis_correction(&cell, temperature, voltage); //
if(cells_equal(cell, cur_cell)) { // - ,
set_next_cell(NULL_CELL);
no_cur_cell_time = 0; // ,
} else {
if(no_cur_cell_time++ > CELL_CHANGE_TIMEOUT) { // CELL_CHANGE_TIMEOUT+1 cur_cell,
change_cell(cell); // ,
} else {
if(cells_equal(next_cell, NULL_CELL) || !cells_equal(next_cell, cell)) { // - ,
set_next_cell(cell);
} else {
if(++cell_change_time >= CELL_CHANGE_TIMEOUT) { // , , ,
change_cell(cell);
}
}
}
}
}
}
}
}
// watchdog
ISR(WDT_vect) {
WDTCR |= (1 << WDTIE); // watchdog ""
}
// , ADSC measure_adc()
EMPTY_INTERRUPT(ADC_vect);
//
int main(void) {
init_pins(); //
init_interrupts(); // watchdog
while(true) { // ,
set_sleep_mode(SLEEP_MODE_PWR_DOWN); //
sleep_cpu(); // watchdog
main_proc(); //
}
}
: L:0x6A, H:0xFF.
. , – , – . , . :
, .
, . , . , , .
, - , . , , . , - , , , , . .. - , , . . . , , .
, . , , , 12.5 , , 12.4 . . , .
, , , . , . «» 8-9 .
, . «» , . , , «» , - (, , , , , - ).
, +50⁰C , . , , , . .
«», , (watchdog). .
, – . . Watchdog , , , . , , , watchdog. , , .
. 1006 , - .
, , . , O2, , Os , 1024 . -, .
.