Você está na página 1de 15

UNIVERSIDADE FEDERAL DO ABC

ESTI013-17 SISTEMAS MICROPROCESSADOS


Prática 05: Conversão de sinais ANALÓGICO-DIGITAIS.

Luciano Henrique Lacerda de Araújo RA:11050314


Rodrigo de Carvalho Santos RA:11000714

3º Quadrimestre
Santo André, Novembro – 2019
1. INTRODUÇÃO

Os microcontroladores, apesar de processarem seus dados de forma digital,


permitem a entrada dos dados advindos do mundo físico exterior, cuja natureza é,
em geral, analógica. Desta forma, torna-se necessário o uso de periféricos que
façam a conversão analógico-digital para tais dados de entrada.
Nesta atividade pratica, foram inseridos valores de tensão na faixa 0 – 3,3 V e foi
utilizada a técnica de varredura, para a verificação periódica da amplitude de
entrada, condicionada ao pressionamento do botão PB6, permitindo a conversão em
dados digitais em tempo real a cada acionamento mecânico. Após o
processamento, o dado de entrada digitalizado era exibido no display de sete
segmentos. Em seguida, foram realizadas alterações no código de modo que a
varredura para leitura dos dados de entrada fosse feita periodicamente e
independente do acionamento mecânico e pela interrupção gerada pelo canal ADC.
2. FUNDAMENTAÇÃO

Como descrito na introdução na seção anterior, na prática desenvolvida, o valor


convertido digitalmente irá ser transmitido para o display de sete segmentos TOF-
2481BMR-N. Para que essa transmissão ocorra, devido a arquitetura do display,
deve-se transmitir os dados de forma paralela, e para tanto, utiliza-se, na placa, o
chip 74HC595, capaz de receber dados de forma serial e transmiti-los de forma
paralela.
Os sistemas embarcados são compostos por diversos periféricos, que precisam
se comunicar com o mundo exterior e com o processador principal. Internamente,
processadores, memória e periféricos usam barramentos que interconectam os
diferentes dispositivos formando um subconjunto interno de interfaceamento [2].
De maneira geral, os periféricos geram dados de forma intermitente que devem
ser processados ou atendidos pela CPU, o que é chamado “servicing”. Há duas
maneiras de a CPU atender os dados gerados: varredura (polling), na qual a CPU
verifica a existência de dados novos, naturalmente gastando tempo de
processamento para tanto, e a interrupção, na qual o periférico externamente
comunica a CPU sobre a existência de novos dados, fazendo com que a CPU
interrompa o processo em andamento para atender à interrupção [2].
Outro importante aspecto trabalhado na prática foi a conversão analógico-digital.
De forma breve a conversão analógico-digital é um grupo de circuitos e técnicas
para discretizar e quantificar um sinal analógico, em muitos dos casos provenientes
de sensores/transdutores em um sinal digital, o qual poderá ser modificado e
operado pelo sistema microprocessado.
Umas das abordagens utilizadas por estes conversores é a comparação, ou
seja, produz-se um sinal analógico por meio de um conversor digital-analógico e
então compara-se este sinal com o sinal analógico até que a comparação não possa
ser melhor considerando os níveis de quantificação trabalhados.
No ARM (STM32F103C8), por exemplo, utiliza-se a técnica de comparações
sucessivas, na qual varia-se a alternância dos bits desde o MSB até o LSB para
verificar qual é a combinação que mais se aproxima do sinal analógico amostrado.
Para além do escopo principal da operação de conversão, seguem ainda algumas
carcaterísticas importantes sobre o ADC no ARM (STM32F103C8), [3]
1. 2 conversores analógico-digital;
2. 12 bits de aproximação sucessiva (usa 14 clocks devido ao Sample &
Hold);
3. Gera interrupção ao final da conversão;
4. Conversão simples (conversão uma única vez) ou contínua (repete o
processo de conversão logo após sua conclusão);
5. Samplingtime (taxa de leitura) programável para cada canal;
6. Opcionalmente, pode-se disparar conversão por sinal externo;
7. Pode gerar DMA durante uma conversão regular para um canal;
8. Fonte para ADC: 2,4 V-3,6 V; valor do sinal analógico.

Figura 1: Esquemático de bloco do conversor ADC do STM32F103C8 [3].


3. METODOLOGIA

Conforme instruído no roteiro da prática [1], utilizou-se o código disponibilizado


para se entender a conversão analógico-digital por meio da varredura (polling).
Nesta estratégia de conversão, configurou-se uma interrupção externa por meio do
pino PB6. Neste pino, está conectado o push button da placa.
Quando a interrupção é acionada, a rotina de conversão analógico-digital é
chamada e então o sinal no pino PA0 é convertido digitalmente, levando em conta a
alimentação de 3,3V. Dada a conversão do sinal de tensão analógico, segue a
separação dos valores dos dígitos para a transmissão para o display de sete
segmentos.
Posteriormente, a proposta da prática seria implementar a varredura dos valores
do conversor analógico-digital, de maneira automática, a cada 250 ms [1]. Esta
implementação foi feita partindo da estrutura utilizada para o polling com o pino
PB6, apenas adotando a mesma estratégia utilizada em práticas anteriores de
contagem do tempo por meio do timer Systick, usando a função milis() e uma
constante de tempo para definir o intervalo de varredura para a conversão.
Por fim, como a conversão analógico-digital por meio da varredura consome
recursos de processamento da CPU desnecessariamente e os canais de conversão
analógico-digital do STM32F103C8 permitem que interrupções sejam disparadas ao
final da conversão, segue a última proposta de prática como um desafio:
implementar a conversão analógico-digital por meio de interrupção.
Para a implementação da interrupção utilizou-se o plug-in STM32CubeMX. Este
plug-in é API em que fica disponível ao usuário um ambiente de configuração dos
clocks e pinos, por meio de caixas de diálogo e listas de opções. Apenas
aproveitando a oportunidade de explorar este plug-in na última prática, utilizou-se
este ambiente para configurar o canal de conversão analógico-digital e habilitar a
interrupção pelo ao fim da conversão, gerando o código e descarregando na placa
posteriormente.
4. ANÁLISE

Para facilitar a organização do código, todas as funções, exceto as interrupções,


foram escritas no arquivo principal. Após a declaração das configurações e
constantes, além do protótipo das funções, inicia-se a função principal (main.c), com
a configuração dos periféricos, do clock e dos pinos.

// funções mudadas para o arquivo "funcoes.c" para melhor organizar o projeto


setup_RCC(); // ini: habilitar CLKs dos periféricos
setup_GPIOs(); // setup GPIOs interface LEDs
setup_INT_externa(); // setup Interrupcao externa
setup_ADC_conv(); // setup do conversor ADC
setup_systick(FREQ_TICK); // set timers p/ 1 ms (1000 Hz)
reset_pin_GPIOs(); // garante pinos GPIOs inicializados
reset_modo_oper(); // zera var modo_oper

Em seguida são declaradas as variáveis utilizadas no loop infinito, são as


variáveis de decomposição do valor de entrada em dígitos individuais, de
armazenamento dos dados após conversão em hexadecimal para a exibição no
display, de serialização dos dados, de armazenamento dos dados após conversão
para miliVolts, de registro do tempo decorrido desde a última varredura e de
atualização do valor exibido no display em cada dígito após cada varredura.
// vars e flags de controle do programa no superloop...
int
milADC = 0, // ini decimo de seg
cenADC = 0, // ini unidade de seg
decADC = 0, // ini dezena de seg
uniADC = 0; // ini unidade de minuto

int16_t
val7seg = 0x00FF, // inicia 7-seg com 0xF (tudo apagado)
serial_data = 0x01FF, // dado a serializar (dig | val7seg)
val_adc = 0; // valor lido no ADC

uint32_t miliVolt = 0x0, // val adc convertido p/ miliVolts


tIN_varre = 0; // registra tempo última varredura

// var de estado que controla a varredura (qual display é mostrado)


static enum {DIG_UNI, DIG_DEC, DIG_CENS, DIG_MILS} sttVARRE=DIG_MILS;

Com as variáveis definidas e configurações prévias realizadas, inicia-se o loop


infinito contendo 3 tarefas. A primeira tarefa realiza a operação de polling por meio
da interrupção configurada no pino PB6, vide pratica 04, quando há uma atualização
por varredura do valor de entrada lido, convertendo o novo valor analógico para o
formato digital, trocando-se os estados dos LEDs PC13 (LIGA-> DESLIGA) e PC14
(DESLIGA->LIGA). Ainda, neste trecho do código separam-se os valores digitais
recém-atualizados, a partir da entrada analógica, sendo então convertidos em
miliVolts e decomposto nos dígitos separados para serem exibidos no display de
sete segmentos.

// tarefa #1: se (modo_oper=1) faz uma conversão ADC


if (get_modo_oper()==1)
{
GPIO_WriteBit(GPIOC, GPIO_Pin_14, Bit_RESET); // apaga o LED PC14
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET); // liga o LED PC13
// dispara por software uma conversão ADC
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // habilita conversão ADC1
// espera que a conversão termine (polling)
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET ) {}
//if (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))
//{
val_adc = ADC_GetConversionValue(ADC1); // lê último valor convertido
ADC_ClearFlag(ADC1, ADC_FLAG_EOC); // limpa flag no fim conversão
// ADC1->SR = ~(uint32_t)ADC_FLAG_EOC; // limpa flag diretamente
// }
miliVolt = val_adc*3300/4095; // converte p/ mili Volts
uniADC = miliVolt/1000; // define valor unidade V
decADC = (miliVolt-uniADC*1000)/100; // décimo de V
cenADC = (miliVolt-uniADC*1000-decADC*100)/10; // centésimo V
milADC = miliVolt-uniADC*1000-decADC*100-cenADC*10; // milésimo V
reset_modo_oper(); // zera var modo_oper
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);// apaga o LED PC13
GPIO_WriteBit(GPIOC, GPIO_Pin_14, Bit_SET);// liga o LED PC14

tIN_ADC_varre = milis();
} // fim da tarefa #1 (conversão ADC se modo=1)

A segunda tarefa que é realizada é o tratamento dos valores convertidos


digitalmente para a transmissão para o display de sete segmentos. A variável
sttVARRE é atualizada a cada dígito para implicar na alteração do próximo, e caso o
valor atribuído ao dígito mais significativo considerado não seja maior do que zero, o
dígito correspondente do display é desconsiderado e apagado até, no mínimo, a
varredura seguinte.
Nesse trecho do código, em cada display há a declaração de seu respectivo
endereço, baseando-se no datasheet do TOF-2481BMR-N. Então, converte-se o
valor decimal do dígito a ser enviado em hexadecimal e por fim estes valores são
concatenados (endereço+dígito) para a transmissão serial.
// tarefa #2 FAZ SEMPRE: qdo milis() > DELAY_VARRE ms, desde a última mudança
if (milis()-tIN_varre > DELAY_VARRE ) // se ++0,1s atualiza o display
{
switch(sttVARRE) // teste e escolha de qual DIG vai varrer
{
case DIG_MILS:
{
sttVARRE = DIG_CENS; // ajusta p/ prox digito
serial_data = 0x0001; // display #1
val7seg = conv_7_seg(milADC);
break;
}
case DIG_CENS:
{
sttVARRE = DIG_DEC; // ajusta p/ prox digito
serial_data = 0x00002; // display #2
if(cenADC>0 || decADC>0 || uniADC>0)
{
val7seg = conv_7_seg(cenADC);
} else {
val7seg = conv_7_seg(DIGITO_APAGADO);
}
break;
}
case DIG_DEC:
{
sttVARRE = DIG_UNI; // ajusta p/ prox digito
serial_data = 0x0004; // display #3
if(decADC>0 || uniADC>0)
{
val7seg = conv_7_seg(decADC);
} else {
val7seg = conv_7_seg(DIGITO_APAGADO);
}
break;
}
case DIG_UNI:
{
sttVARRE = DIG_MILS; // ajusta p/ prox digito
serial_data = 0x0008; // display #3
if(uniADC>0)
{
val7seg = conv_7_seg(uniADC);
val7seg &=0x7FFF; // liga o ponto decimal
} else {
val7seg = conv_7_seg(DIGITO_APAGADO);
}
break;
}
}
tIN_varre = milis(); // tmp atual em que fez essa varredura
serial_data |= val7seg; // OR com val7seg = dado a serializar
serializar(serial_data); // serializa dado p/74HC595 (shift reg)
} // -- fim da tarefa #2, rotina que faz de varredura do display
} // -- fim do loop infinito
} // ------------------------ FIM PROG MAIN ---------------------------
Destaca-se que a transmissão para os display’s de sete segmentos é feita
sempre tendo em vista um dos display’s de sete segmentos, de tal modo que a
varredura é tão rápida entre os quatros que a impressão visual dada é a de que
transmissão contínua aos quatro. A velocidade da transmissão é definida pela
constante DELAY_VARRE.
Para a tarefas seguinte, a realização da varredura de maneira automática a
cada 250 ms, apenas substiutui-se a condição inicial, disparada pela interrupção
gerada pelo pino PB6 para a contagem controlada pelo timer Systick, por meio da
função milis().
uint32_t tIN_ADC_varre = 0;

// tarefa #1: se (modo_oper=1) faz uma conversão ADC


if (milis()-tIN_ADC_varre > DELAY_ADC)
{
GPIO_WriteBit(GPIOC, GPIO_Pin_14, Bit_RESET); // apaga o LED PC14
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET); // liga o LED PC13
// dispara por software uma conversão ADC
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // habilita conversão ADC1
// espera que a conversão termine (polling)
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET ) {}
//if (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))
//{
val_adc = ADC_GetConversionValue(ADC1); // lê último valor convertido
ADC_ClearFlag(ADC1, ADC_FLAG_EOC); // limpa flag no fim conversão
// ADC1->SR = ~(uint32_t)ADC_FLAG_EOC; // limpa flag diretamente
// }
miliVolt = val_adc*3300/4095; // converte p/ mili Volts
uniADC = miliVolt/1000; // define valor unidade V
decADC = (miliVolt-uniADC*1000)/100; // décimo de V
cenADC = (miliVolt-uniADC*1000-decADC*100)/10; // centésimo V
milADC = miliVolt-uniADC*1000-decADC*100-cenADC*10; // milésimo V
reset_modo_oper(); // zera var modo_oper
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);// apaga o LED PC13
GPIO_WriteBit(GPIOC, GPIO_Pin_14, Bit_SET);// liga o LED PC14

tIN_ADC_varre = milis();
} // fim da tarefa #1

A terceira tarefa foi realizada com auxílio do plug-in STM32CubeMX. Neste


ambiente configurou-se os canais de conversão analógico-digitais ADC 1 e 2 para
gerarem interrupções quando do fim da conversão do valor. No mais, a utilização do
plug-in é bem simples uma vez que a interface auxilia a configuração do hardware
conforme o desejado, gerando o código respectivo para atender a configuração
feita.
/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/


/* USER CODE BEGIN Includes */
#define SDT595 GPIO_PIN_13 // SERIAL DATA para 595
#define SCK595 GPIO_PIN_1 // SERIAL CLOCK para 595
#define SRC595 GPIO_PIN_0 // REGISTER CLOCK para 595
#define DT_VARRE 7 // kte (ms) intervalo varreduta
#define DISP_TIPO 0x0 // DISP_TIPO = 0 - anodo comum
#define DIGITO_APAGADO 0x10 // tudo apagado no display
#define MODO_DISP_7SEG 0 // MODO 7-seg =0 ANODO; =1 CATODO comum
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/


/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/


/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/


/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/


ADC_HandleTypeDef hadc1;

/* USER CODE BEGIN PV */


static uint16_t volatile val_adc = 0; // recebe val do ADC
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/


void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
/* USER CODE BEGIN PFP */
void set_modo_oper(int); // seta modo_oper (no stm32f1xx_it.c)
int get_modo_oper(void); // obtém modo_oper (stm32f1xx_it.c)
// -- as 3 funções seguintes estão na seção /USER CODE 4 -- //
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc); // resp callback ACD
void serializar(int ser_data); // prot fn serializa dados p/ 74HC595
int16_t conv_7_seg(int NumHex); // prot fn conv valor --> 7-seg
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/


/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/* MCU Configuration--------------------------------------------------------*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();

/* USER CODE BEGIN Init */

/* USER CODE END Init */

/* Configure the system clock */


SystemClock_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals */


MX_GPIO_Init();
MX_ADC1_Init();
/* USER CODE BEGIN 2 */
HAL_GPIO_WritePin(GPIOB, SDT595, GPIO_PIN_RESET); // SDATA=0
HAL_GPIO_WritePin(GPIOB, SCK595, GPIO_PIN_RESET); // SCK=0
HAL_GPIO_WritePin(GPIOB, SRC595, GPIO_PIN_RESET); // RCK=0
// definir as vars para o programa quando em loop
int
milADC = 0, // ini milésimo do val ADC
cenADC = 0, // ini centésimo do val ADC
decADC = 0, // ini décimo do val ADC
uniADC = 0; // ini unidade do val ADC
int16_t val7seg = 0x00FF; // 7-seg com 0xF (tudo apagado)
int16_t serial_data = 0x01FF; // dado a serializar (dig | val7seg)
uint32_t miliVolt = 0x0, // val adc convertido p/ miliVolts
tIN_varre = 0; // registra tempo última varredura
static enum {DIG_UNI, DIG_DEC, DIG_CENS, DIG_MILS} sttVARRE=DIG_MILS;
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */


if (get_modo_oper()==1)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET); // apaga o LED
PC14
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET); // liga o LED PC13
// dispara por software uma conversão ADC
set_modo_oper(0); // muda modo_oper p/ 0
HAL_ADC_Start_IT(&hadc1); // dispara ADC p/ conversão por interrupção
}

//#2 converte o valor ADC para milivolts (decimal, para lermos no 7-seg)
if (get_modo_oper()==2) // entra qdo valor val_adc atualizado
{
// converter o valor lido em decimais p/ display
miliVolt = val_adc*3300/4095;
uniADC = miliVolt/1000;
decADC = (miliVolt-(uniADC*1000))/100;
cenADC = (miliVolt-(uniADC*1000)-(decADC*100))/10;
milADC = miliVolt-(uniADC*1000)-(decADC*100)-(cenADC*10);
set_modo_oper(0); // zera var modo_oper
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);// apaga o LED PC13
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_SET);// liga o LED PC14
}
// tarefa #3 FAZ SEMPRE: qdo milis() > DELAY_VARRE ms, desde a última
mudança
if ((HAL_GetTick()-tIN_varre) > DT_VARRE) // se ++0,1s atualiza o display
{
tIN_varre = HAL_GetTick(); // salva tIN p/ prox tempo varredura
switch(sttVARRE) // teste e escolha de qual DIG vai varrer
{
case DIG_MILS:
{
sttVARRE = DIG_CENS; // ajusta p/ prox digito
serial_data = 0x0001; // display #1
val7seg = conv_7_seg(milADC);
break;
}
case DIG_CENS:
{
sttVARRE = DIG_DEC; // ajusta p/ prox digito
serial_data = 0x00002; // display #2
if(cenADC>0 || decADC>0 || uniADC>0)
{
val7seg = conv_7_seg(cenADC);
} else {
val7seg = conv_7_seg(DIGITO_APAGADO);
}
break;
}
case DIG_DEC:
{
sttVARRE = DIG_UNI; // ajusta p/ prox digito
serial_data = 0x0004; // display #3
if(decADC>0 || uniADC>0)
{
val7seg = conv_7_seg(decADC);
} else {
val7seg = conv_7_seg(DIGITO_APAGADO);
}
break;
}
case DIG_UNI:
{
sttVARRE = DIG_MILS; // ajusta p/ prox digito
serial_data = 0x0008; // display #3
if(uniADC>0)
{
val7seg = conv_7_seg(uniADC);
val7seg &=0x7FFF; // liga o ponto decimal
} else {
val7seg = conv_7_seg(DIGITO_APAGADO);
}
break;
}
} // fim case
tIN_varre = HAL_GetTick(); // tmp atual em que fez essa varredura
serial_data |= val7seg; // OR com val7seg = dado a serializar
serializar(serial_data); // serializa dado p/74HC595 (shift reg)
} // -- fim da tarefa #2 - varredura do display

}
/* USER CODE END 3 */
}

Note na rotina principal, para além das novas funções utilizadas devido as novas
bibliotecas consumidas, as linhas em destaque amarelo, pois estas linhas são onde
o canal ADC é inicializado (configuração de modo de scan, por exemplo) e
configurado para que funcione no modo de interrupção. Em seguida, ainda no
arquivo principal, são configurados o ADC e a função de serialização dos dados e
de conversão dos dados para hexadecimal com uma estrutura switch-case.

static void MX_ADC1_Init(void)


{

/* USER CODE BEGIN ADC1_Init 0 */

/* USER CODE END ADC1_Init 0 */

ADC_ChannelConfTypeDef sConfig = {0};

/** Common config


*/
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
No arquivo "stm32f1xx_it.c", como nas atividades anteriores, são configurados o
timer Systick e a sua interrupção, a interrupção gerada pela conversão analógico-
digital do canal ADC 1 e também é tratado o problema de boucing.

void ADC1_2_IRQHandler(void)
{
HAL_ADC_IRQHandler(&hadc1);
}
void EXTI9_5_IRQHandler(void)
{
if((HAL_GetTick()-tIN_IRQ6)>DT_DEBOUNCING)
{
tIN_IRQ6 = HAL_GetTick(); // tIN (ms) da última IRQ6
if (HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_6)==0)
{
++ modo_oper; // incrementa modo operação
if (modo_oper>MAX_MODO_OPER) modo_oper=0;// se >MAX voltar modo_oper=0
}
}

HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_6);
}
Finalmente, são estruturadas as funções de configuração e retorno da variável
modo_oper, impedindo que a variável supere o valor de MAX_MODO_OPER (2,
definido no cabeçalho), por ser o número de tarefas condicionais onde a variável é
testada).

void set_modo_oper(int x)
{
if(x>MAX_MODO_OPER) // se x maior MAX permitido

{
modo_oper=MAX_MODO_OPER; // set apenas com max
}else if(x<0) // se x menor que 0
{
modo_oper=0; // set com 0
}else // valor no intervalo 0-MAX
{
modo_oper=x; // modifica modo_oper
}
}
// fn que qpenas retorna o valor da var modo_oper
int get_modo_oper(void){
static int x; // var local recebe modo_oper
// OBS: seção crítica, desabilitamos todas as IRQs p/ atualizar var
__disable_irq(); // desabilita IRQs
x = modo_oper; // faz x = modo_oper
__enable_irq(); // volta habilitar IRQs
return x; // retorna x (=modo_oper)
}
5. CONCLUSÕES

A delegação de tarefas mais simples para periféricos especializados, conforme


aprendido em práticas anteriores, permitiu à CPU a obtenção de um desempenho
satisfatório no processamento de dados do mundo exterior. O sistema demandou
um cuidado maior no tratamento do procedimento sequencial a ser tomado, dado
que a entrada se dá em tempo contínuo enquanto o processamento deve ser feito
em instantes específicos. A utilização do conversor analógico-digital utilizada em
conjunto com a exibição do valor no display de 7 segmentos permitiu a percepção
de como a placa pode proporcionar o monitoramento de uma variável em um
processo real, o que foi automatizado com a utilização da varredura periódica, mais
adequada para ambientes reais.

6. REFERÊNCIAS
[1] RANHEL, João. Sistemas Microprocessados: Apostila com práticas e foco nos
processadores ARM CORTEX, ver. 3, out. 2019.

[2] RANHEL, João.Sistemas Microprocessados:Comunicação Paralela. 39p. Notas de


Aula.

[3] RANHEL, João.Sistemas Microprocessados:DAC, ADC e DMA. 42p. Notas de


Aula..

Você também pode gostar