Meranie dĺžky impulzu
Zo stránky SensorWiki
Úloha
- Vytvoriť simulátor PWM signálu snímača teploty: SMT 160-30, resp. SMT 172
- TC0 bude na pine PD5 generovať PWM signál s 𝑓_𝑃𝑊𝑀=1𝑘𝐻𝑧 a plnením v intervale DC = (0,1 až 0,9).
- DC budeme zadávať v %.
- Na meranie parametrov PWM signálu: T1 - čas v log. 1 a T_opak – trvanie jednej periódy PWM signálu použijeme TC1 (16b). TC1 nastavíme do módu „odpamätanie“ stavu počítadla pri výskyte hrany na pine PB.0. Využijeme ISR().
- Pomocou TC2, bude generovať presnú periodu vzorkovania. Periódu opakovania výpisov, ako aj zmeny plnenia o definovaný prírastok, napr. 1, budeme realizovať s krokom 0,5sek. Využijeme ISR().
- Výpisy na LCD, resp. terminál treba realizovať vo formáte, xx,x. (Pevná rádova čiarka). Pri výpočtoch nemôže byť použitá float aritmetika.
- Vo výpisoch sa musí objaviť: Nastavené plnenie. Trvanie T_1, resp. T_opak v SC a us. Ako aj plnenie v % vo formáte: xx,x. Rovnako aj danému plneniu odpovedajúca teplota vo formáte +-xx,x °C .
- Ako úloha naviac: Navrhnite filter typu kĺzavý priemer z 8-ich vzoriek.
Slajdy k teoretickému rozboru cvičenia
//Hlavný program
#include <avr/io.h>
#include <avr/interrupt.h>
#include "p_f_1.h"
#include "p_f_2.h"
// deklarovanie premenných
int main(void){
/* Ini PORT‘s, TCx, prerušení
Konfiguracia UART:Tx, Rx */
ini_usart_0(MYUBRR);
ini_TC0(); ini_TC1(); ini_TC2();
sei(); // Enable interrupts in general
sprintf(Riadok,"Meranie plnenia impulzu \r\n" );
zob_text_UART(Riadok);
/* main loop */
while (1) {
if(flag_Vypisov){
flag_Vypisov = 0;
Vypis();
Zmena_plnenia(); // DC = (10 az 90 %)
}
}
}
// ********************************* p_f_1.h
/*
* p_f_1.h
*/
#ifndef P_F_1_H_
#define P_F_1_H_
#define F_CPU 16000000UL /* Define CPU frequency here 16MHz */
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdlib.h>
void zob_text_UART(char *);
void ini_usart_0(unsigned int );
void USART_Transmit( unsigned char );
void zob_text(char *);
void Zmena_plnenia(void);
unsigned char Prepocet_plnenia_PWM(unsigned char );
void Vypis(void);
extern char Riadok[];
extern volatile unsigned int T1_no_vz;
extern volatile unsigned int T1_st_vz;
extern volatile unsigned int pl_PWM_pocitane_Percent;
extern volatile unsigned long T_log_1;
extern volatile unsigned long T_log_1_us;
extern volatile long T_opak;
extern volatile int T_M;
extern unsigned char DC_PWM_percent;
extern uint8_t T_vypis; // cca 0,5 sek , potom doladim
#define BAUD 115200
//UCSR0A.U2X0 = 1
#define MYUBRR
#endif /* P_F_1_H_ */
// ********************************* p_f_1.c
/*
* p_f_1.c
*/
#include "p_f_1.h"
#include "p_f_2.h"
// Inicializacia UARTu
void ini_usart_0(unsigned int mybr){
UBRR0 = mybr;
...
}
void zob_text_UART(char *s){
register unsigned char c;
while((c = *s++)) USART_Transmit(c); // retazec konci "nulou"
}
void USART_Transmit( unsigned char data ){
/* Wait for empty transmit buffer */
while ( !( UCSR0A & (1<<UDRE0)) );
/* Put data into buffer, sends the data */
UDR0 = data;
}
void Vypis(void){
// formátovaný výpis
//printf("Plnenie:?????? ", DC_PWM_percent, T_log_1, T_opak );
Výpis:Plnenie: dd%, ddd [SC], ddd [SC]
Výpis:Plnenie: dd%, ddd [us], ddd [us]
printf("Plnenie:?????? ", DC_PWM_percent, pl_PWM_pocitane_Percent );
Výpis:Plnenie: dd%, dd,d%
zob_text_UART(Riadok);
}
void Zmena_plnenia(void){ // rozsah 10 az 90 %
DC_PWM_percent+=?;
if (DC_PWM_percent >90)DC_PWM_percent = 10;
// prepocitam rozsah v percentach na odpovedajuce cislo
if (DC_PWM_Percent > 90) DC_PWM_Percent = 10;
OCR0B = f(DC_PWM_Percent);
}
unsigned char Prepocet_plnenia_PWM(unsigned char pln_per){
...
}
// ********************************* p_f_2.h
/*
* p_f_2.h
*/
#ifndef P_F_2_H_
#define P_F_2_H_
#define set_bit(Adress,Bit) (Adress |= (1<<Bit))
#define clear_bit(Adress,Bit) (Adress &= ~(1<<Bit))
#define toggle_bit(Adress,Bit) (Adress ^= (1<<Bit))
extern volatile unsigned char poc_T_vypis ;
extern volatile unsigned char flag_Vypisov ;
#define f_opak_TC0 1000 // 1000 Hz <-> 1ms
#define N_D_TC0 // Delic pre TC0
#define OCR0A_f_opak_TC0 // Vysledkom je perioda opakovania 1ms !!!!!
#define f_opak_TC2 500 // 500 Hz -> 2ms
#define N_D_TC2 // Delic pre TC2
#define OCR2A_f_opak_TC2 // Vysledkom je 2ms casova vzorka !!!!!
#define T__050 250 // 0,5 sek = 250 * 2ms
void ini_TC0(void);
void ini_TC1(void);
void ini_TC2(void);
#endif /* P_F_2_H_ */
// ********************************* p_f_2.c
/*
* p_f_2.c
*
* Created: 4/12/2021 11:29:22 AM
* Author: Admin
*/
#include <avr/io.h>
#include "p_f_1.h"
#include "p_f_2.h"
void ini_TC0(void){
// Nastavenie TC0
set_bit(DDRD,PIND5); //OC0B PWM pin
// 7 6 5 4 3 2 1 0
// COM0A[1:0] COM0B[1:0] WGM0[1:0]
TCCR0A = ??????;// OC0B PWM mod = ?
// 7 6 5 4 3 2 1 0
// WGM02 CS0[2:0]
TCCR0B = ??????;// fosc/??
OCR0B = 𝑓("DC_PWM_percent " );
// nastvenie frekvencie opakovania na 1ms
OCR0A = OCR0A_f_opak_TC0;
}
void ini_TC1(void){
// Timer1 Capture
DDRB &= ~(1<<DDB0); //ICP1 = PORTB.0, input
PORTB |= (1<<PORTB0); // Pullup Rezistor
// Nastavenie TC1
// 7 6 5 4 3 2 1 0
// WGM12 CS1[2:0]
// fTC1 = f(fosc) chceme max. presnosť merania
TCCR1B ?= ????;
TCCR1B ?= ????; // odchytenie na nabeznu hranu
TIMSK1 ?= ????; // povolenie prerusenia od capture T1
// sei(); pre všetky naraz
}
void ini_TC2(void){
// Nastavenie TC2
// 7 6 5 4 3 2 1 0
// COM2A[1:0] COM2B[1:0] WGM2[1:0]
TCCR2A ? = ????;// OC2B PWM mod = 7
// 7 6 5 4 3 2 1 0
// WGM02 CS0[2:0]
TCCR2B ?= ????;// fosc/??
// nastavenie frekvencie opakovania na 2ms
OCR2A ? = OCR2A_f_opak_TC2;
// Enable interrupts @ overflow TC2 MOD 7
TIMSK2 ? = ????;
// sei(); pre všetky naraz
}
ISR(TIMER2_OVF_vect)
{ /// tato slucka sa vykona kazde 2,0ms
OCR2A = OCR2A_f_opak_TC2;
//toggle_bit(PORTD,PIND2); //PD2 - change
poc_T_vypis--;
if (!poc_T_vypis) {
// prednastavim pocitadlo vypisov na 0,5s
poc_T_vypis = T__050;
flag_Vypisov = 1;// nastavim priznak vypisov
//toggle_bit(PORTD,PIND2); //PD2 - change
}
}
ISR(TIMER1_CAPT_vect){
// globalne prerusenie je zakazane
// POCITADLO SA INKREMENTUJE KAZDU ?us
if(TESTUJEM HRANU){// bola nábežna hrana
....; // tu prepnem na dobežnu hrana
T1_st_vz = T1_no_vz;
T1_no_vz = ICR1; // odpamätám nový “čas“
T_opak = ... ;
pl_PWM_pocitane_Percent = f(T_log_1,T_opak);
T_M = f( (T_log_1 ,T_opak);
} else {// bola dobežna hrana
....; // tu prepnem na nábežnu hrana
T_log_1 = ICR1 - T1_no_vz;
T_log_1_us =f(.....).
}
}
Literatúra
- SMT 172 Temperature sensor Specification sheet
- SMT 160-30 Temperature sensor Specification sheet
- AVR130: Setup and Use the AVR® Timers. Aplication Note, Atmel Corporation 2002.
+ software download - AVR135: Using Timer Capture to Measure PWM Duty Cycle. Aplication Note, Atmel Corporation 2005.
+ software download - Pozn. pre autora: staršia verzia tohoto cvika je tu Meranie dĺžky impulzu 2