Простой измеритель LCF

Обсуждаем цифровые устройства...
Ответить
agatkon1974
Родился
Сообщения: 1
Зарегистрирован: Чт фев 26, 2026 17:21:45

Простой измеритель LCF

Сообщение agatkon1974 »

Представляю Вашему вниманию простой FLC метр.
Сначала код программы для Atmega8.

Код: Выделить всё

#define F_CPU 8000000UL
#include <asf.h>
#include <stdint-gcc.h>
#include <util\delay.h>
#include "lcd.h"
volatile uint16_t frequency = 0;
uint32_t F0 = 5028;
uint32_t C0 = 1000;
uint32_t L0 = 100;
uint32_t result;
uint64_t temp;
volatile convc = 0;

ISR(TIMER0_OVF_vect){
	static unsigned char ovf_count = 0;
	ovf_count++;

	if(ovf_count >= 49)   // 100 мс
	{
		convc++;
		frequency = TCNT1/10;
		TCNT1 = 0;
		ovf_count = 0;
	}
}

// Функция преобразования значений выводимых на дисплей в читабельный вид
static void int_to_ascii(int inum,char *outbuf,signed char decimalpoint_pos,signed char spacepadd){
	signed char i,j;
	char chbuf[16];
	j=0;
	while(inum>9 && j<15){
		// zero is ascii 48:
		chbuf[j]=(char)48+ inum-((inum/10)*10);
		inum=inum/10;
		j++;
		if(decimalpoint_pos==j){
			chbuf[j]='.';
			j++;
		}
	}
	chbuf[j]=(char)48+inum; // most significant digit
	decimalpoint_pos--;
	while(j<decimalpoint_pos){
		j++;
		chbuf[j]='0';
	}
	if (spacepadd && j > (decimalpoint_pos+2)){
		// no leading space padding needed
		spacepadd=0;
	}
	if(decimalpoint_pos==j){
		j++;
		chbuf[j]='.';
		j++;
		chbuf[j]='0';
	}
	if (spacepadd){
		j++;
		chbuf[j]='*'; // leading space padding: "9.50" becomes " 9.50"
	}
	// now reverse the order
	i=0;
	while(j>=0){
		outbuf[i]=chbuf[j];
		j--;
		i++;
	}
	outbuf[i]='\0';
}

int main (void)
{
	char out_buf[20+1];
	/* Insert system clock initialization code here (sysclk_init()). */
    sei();
	board_init();
    
	/* Insert application code here, after the board has been initialized. */
	while(1){
	  lcd_clrscr();
	  if (convc > 2){
		  lcd_puts("Lx= ");
		  temp = (uint64_t)F0 * F0;
		  temp = temp * L0;                
		  temp = temp / ((uint64_t)(frequency + F_POT) * (frequency + F_POT));
		  result = (uint32_t)temp - L0;
		  int_to_ascii(result,out_buf, 0, 0);
		  lcd_puts(out_buf);
		  lcd_puts(" uH");
	  }
	  else {
		  lcd_puts("CALCULATING!");
	  }
	  _delay_ms(100);
	}
}
Формула следующая:
Собираем высокочастотный генератор с образцовыми L0 и C0 (схем полно в интернете, я приведу свою) и подключаем к нему Cx и Lx соответственно.

Формула расчета Cх = (C0 * (F0 * F0)/(Fx * Fx)) - C0;
для расчета Lx = (L0 * (F0 * F0)/(Fx * Fx)) - L0
где: F0 - частота генератора при эталонных С0 и L0, а Fx измеренная частота при подключенном Cx или Lx соответственно.

Далее представлю код заголовочных файлов для работы проги

Код: Выделить всё

#include <asf.h>
#include <board.h>
#include <conf_board.h>
#include "lcd.h"
#include "tm.h"

void board_init(void)
{
	/* This function is meant to contain board-specific initialization code
	 * for, e.g., the I/O pins. The initialization can rely on application-
	 * specific board configuration, found in conf_board.h.
	 */
	init_tm();
	lcd_init(LCD_DISP_ON);
}
Инициализация таймера

Код: Выделить всё

#ifndef TM_H_
#define TM_H_


extern void init_tm(void);


#endif /* TM_H_ */

Код: Выделить всё

#include <avr/io.h>
#include "avr\iom8.h"
/*
 * tm.c
 *
 * Created: 26.02.2026 14:57:51
 *  Author: Shevelev.D
 */ 

void init_tm(void){
	DDRD &= ~(1 << PIND5);   // T1 вход
	// Timer1 - внешний счетчик
	TCCR1B = (1<<CS12)|(1<<CS11)|(1<<CS10);
	// Timer0 prescaler 64
	TCCR0 = (1<<CS01)|(1<<CS00);
	TIMSK |= (1<<TOIE0);
}
Иниациализация LCD LM016

Код: Выделить всё

#ifndef LCD_H_
#define LCD_H_

typedef unsigned char  u08;
typedef unsigned short u16;

/* change these definitions according to your hardware */


#define LCD_DATA_PIN_D7  PB7	/* arbitrary pin for LCD data line D7 */
#define LCD_DATA_PIN_D6  PB2	/* arbitrary pin for LCD data line D7 */
#define LCD_DATA_PIN_D5  PB1	/* arbitrary pin for LCD data line D5 */
#define LCD_DATA_PIN_D4  PB0	/* arbitrary pin for LCD data line D4 */

#define LCD_DATA_DDR_D7 DDRB	/* ddr for LCD data line D7 */
#define LCD_DATA_DDR_D6 DDRB	/* ddr for LCD data line D6 */
#define LCD_DATA_DDR_D5 DDRB	/* ddr for LCD data line D5 */
#define LCD_DATA_DDR_D4 DDRB	/* ddr for LCD data line D4 */

#define LCD_DATA_PORT_D7 PORTB	/* port for LCD data line D7 */
#define LCD_DATA_PORT_D6 PORTB	/* port for LCD data line D6 */
#define LCD_DATA_PORT_D5 PORTB	/* port for LCD data line D5 */
#define LCD_DATA_PORT_D4 PORTB	/* port for LCD data line D4 */

#define LCD_RS_DDR       DDRB   /* ddr for RS line */
#define LCD_RS_PORT      PORTB  /* port for RS line */
#define LCD_RS_PIN       PB6
#define LCD_E_DDR        DDRB  /* ddr for Enable line */
#define LCD_E_PORT       PORTB  /* port for Enable line */
#define LCD_E_PIN        PB4

/* normally you do not change the following */
#define LCD_LINES           2     /* visible lines */
#define LCD_LINE_LENGTH  0x40     /* internal line length */

/* no need to change the next 4 lines. This is standard for HD44780 */
#define LCD_START_LINE1  0x00     /* DDRAM address of first char of line 1 */
#define LCD_START_LINE2  0x40     /* DDRAM address of first char of line 2 */
#define LCD_START_LINE3  0x14     /* DDRAM address of first char of line 3 */
#define LCD_START_LINE4  0x54     /* DDRAM address of first char of line 4 */

/* instruction register bit positions */
#define LCD_CLR             0      /* DB0: clear display */
#define LCD_HOME            1      /* DB1: return to home position */
#define LCD_ENTRY_MODE      2      /* DB2: set entry mode */
#define LCD_ENTRY_INC       1      /*   DB1: 1=increment, 0=decrement  */
#define LCD_ENTRY_SHIFT     0      /*   DB2: 1=display shift on        */
#define LCD_ON              3      /* DB3: turn lcd/cursor on */
#define LCD_ON_DISPLAY      2      /*   DB2: turn display on */
#define LCD_ON_CURSOR       1      /*   DB1: turn cursor on */
#define LCD_ON_BLINK        0      /*     DB0: blinking cursor ? */
#define LCD_MOVE            4      /* DB4: move cursor/display */
#define LCD_MOVE_DISP       3      /*   DB3: move display (0-> cursor) ? */
#define LCD_MOVE_RIGHT      2      /*   DB2: move right (0-> left) ? */
#define LCD_FUNCTION        5      /* DB5: function set */
#define LCD_FUNCTION_8BIT   4      /*   DB4: set 8BIT mode (0->4BIT mode) */
#define LCD_FUNCTION_2LINES 3      /*   DB3: two lines (0->one line) */
#define LCD_FUNCTION_10DOTS 2      /*   DB2: 5x10 font (0->5x7 font) */
#define LCD_CGRAM           6      /* DB6: set CG RAM address */
#define LCD_DDRAM           7      /* DB7: set DD RAM address */
#define LCD_BUSY            7      /* DB7: LCD is busy */

/* set entry mode: display shift on/off, dec/inc cursor move direction */
#define LCD_ENTRY_DEC            0x04   /* display shift off, dec cursor move dir */
#define LCD_ENTRY_DEC_SHIFT      0x05   /* display shift on,  dec cursor move dir */
#define LCD_ENTRY_INC_           0x06   /* display shift off, inc cursor move dir */
#define LCD_ENTRY_INC_SHIFT      0x07   /* display shift on,  inc cursor move dir */

/* display on/off, cursor on/off, blinking char at cursor position */
#define LCD_DISP_OFF             0x08   /* display off                            */
#define LCD_DISP_ON              0x0C   /* display on, cursor off                 */
#define LCD_DISP_ON_BLINK        0x0D   /* display on, cursor off, blink char     */
#define LCD_DISP_ON_CURSOR       0x0E   /* display on, cursor on                  */
#define LCD_DISP_ON_CURSOR_BLINK 0x0F   /* display on, cursor on, blink char      */

/* move cursor/shift display */
#define LCD_MOVE_CURSOR_LEFT     0x10   /* move cursor left  (decrement)          */
#define LCD_MOVE_CURSOR_RIGHT    0x14   /* move cursor right (increment)          */
#define LCD_MOVE_DISP_LEFT       0x18   /* shift display left                     */
#define LCD_MOVE_DISP_RIGHT      0x1C   /* shift display right                    */

/* function set: set interface data length and number of display lines */
#define LCD_FUNCTION_4BIT_1LINE  0x20   /* 4-bit interface, single line, 5x7 dots */
#define LCD_FUNCTION_4BIT_2LINES 0x28   /* 4-bit interface, dual line,   5x7 dots */
#define LCD_FUNCTION_8BIT_1LINE  0x30   /* 8-bit interface, single line, 5x7 dots */
#define LCD_FUNCTION_8BIT_2LINES 0x38   /* 8-bit interface, dual line,   5x7 dots */

#define LCD_MODE_DEFAULT     ((1<<LCD_ENTRY_MODE) | (1<<LCD_ENTRY_INC) )

/* defines which can be used like functions */

/* clear lcd and set cursor to home position */
#define lcd_clrscr() lcd_command(1 << LCD_CLR)


/* set cursor to home position */
#define lcd_home() lcd_command(1 << LCD_HOME)

/*
** function prototypes
*/
extern void lcd_command(u08 cmd);
extern void lcd_gotoxy(u08 x, u08 y); /* line 1 y=0, line 2 y=1 */
extern void lcd_putc(char c); /* print character at current cursor position */
extern void lcd_puts(const char *s); /* print string on lcd (no auto linefeed) */

/* if you hard code a string in the program then you need to decalare
* it like: char *str =PSTR("hello world");
* and then use lcd_puts_p(str);*/
extern void lcd_init(u08 dispAttr); /* initialize the LCD. Call this once*/


#endif /* LCD_H_ */

Код: Выделить всё

#include <avr/io.h>
#include <avr/pgmspace.h>
#include <conf_board.h>
#include "lcd.h"
#include <util/delay.h>

#define lcd_e_high()    sbi(LCD_E_PORT, LCD_E_PIN)
#define lcd_e_low()     cbi(LCD_E_PORT, LCD_E_PIN)

#define lcd_cmd_mode()	cbi(LCD_RS_PORT, LCD_RS_PIN)	/* RS=0  command mode   */
#define lcd_data_mode()	sbi(LCD_RS_PORT, LCD_RS_PIN)	/* RS=1  data mode      */
#define lcd_data_port_out()	{	/* defines all data pins as output */ \
					sbi(LCD_DATA_DDR_D7,LCD_DATA_PIN_D7);\
					sbi(LCD_DATA_DDR_D6,LCD_DATA_PIN_D6);\
				 	sbi(LCD_DATA_DDR_D5,LCD_DATA_PIN_D5);\
				 	sbi(LCD_DATA_DDR_D4,LCD_DATA_PIN_D4);\
				}

#if LCD_LINES==1
#define LCD_FUNCTION_DEFAULT    LCD_FUNCTION_4BIT_1LINE
#else
#define LCD_FUNCTION_DEFAULT    LCD_FUNCTION_4BIT_2LINES
#endif


/* 
** function prototypes 
*/
static void lcd_e_toggle(void);
static void lcd_out_high(u08 d);
static void lcd_out_low(u08 d);

/*
** local functions
*/

int lcd_delay_us(unsigned int us)
/* delay for a minimum of <us> microseconds    */
/* with a 4Mhz crystal */
{
        us = us * 3; // 8 MHz
        while ( us ) us--;
        return(us);
}


static void lcd_out_low(u08 d)
{	/* output low nibble */
	if (d&0x08)  sbi(LCD_DATA_PORT_D7,LCD_DATA_PIN_D7);
		else cbi(LCD_DATA_PORT_D7,LCD_DATA_PIN_D7);
	if (d&0x04)  sbi(LCD_DATA_PORT_D6,LCD_DATA_PIN_D6);
		else cbi(LCD_DATA_PORT_D6,LCD_DATA_PIN_D6);
	if (d&0x02)  sbi(LCD_DATA_PORT_D5,LCD_DATA_PIN_D5);
		else cbi(LCD_DATA_PORT_D5,LCD_DATA_PIN_D5);
	if (d&0x01)  sbi(LCD_DATA_PORT_D4,LCD_DATA_PIN_D4);
		else cbi(LCD_DATA_PORT_D4,LCD_DATA_PIN_D4); 
}
static void lcd_out_high(u08 d)
{	/* output high nibble */ 
	if (d&0x80)  sbi(LCD_DATA_PORT_D7,LCD_DATA_PIN_D7);
		else cbi(LCD_DATA_PORT_D7,LCD_DATA_PIN_D7);
	if (d&0x40)  sbi(LCD_DATA_PORT_D6,LCD_DATA_PIN_D6);
		else cbi(LCD_DATA_PORT_D6,LCD_DATA_PIN_D6);
	if (d&0x20)  sbi(LCD_DATA_PORT_D5,LCD_DATA_PIN_D5);
		else cbi(LCD_DATA_PORT_D5,LCD_DATA_PIN_D5);
	if (d&0x10)  sbi(LCD_DATA_PORT_D4,LCD_DATA_PIN_D4);
		else cbi(LCD_DATA_PORT_D4,LCD_DATA_PIN_D4); 
}

static void lcd_e_toggle(void)
/* toggle Enable Pin */
{
	lcd_e_high();
	//lcd_delay_us(4);
	_delay_ms(1);
	lcd_e_low();
}


static void lcd_write(u08 data, u08 rs)
{
	/* configure data pins as output */
	lcd_data_port_out();

	/* output high nibble first */

	lcd_out_high(data);

	if (rs)
		lcd_data_mode();	/* RS=1: write data            */
	else
		lcd_cmd_mode();	/* RS=0: write instruction     */
	lcd_e_toggle();

	/* output low nibble */
	lcd_out_low(data);

	if (rs)
		lcd_data_mode();	/* RS=1: write data            */
	else
		lcd_cmd_mode();	/* RS=0: write instruction     */

	lcd_e_toggle();

}


static unsigned char lcd_waitcmd(unsigned char cmdwait)
/* this function used to loop while lcd is busy and read address i
 * counter however for this we need the RW line. This function
 * has been changed to just delay a bit. In that case the LCD
 * is only slightly slower but we do not need the RW pin. */
{
        //lcd_delay_us(2);
    _delay_ms(1); 		
	/* the display needs much longer to process a command */
	if (cmdwait){
		//lcd_delay_us(1200);
		_delay_ms(12);
	}
	return (0); 
}


/*
** PUBLIC FUNCTIONS 
*/

void lcd_command(u08 cmd)
/* send commando <cmd> to LCD */
{
	lcd_waitcmd(0);
	lcd_write(cmd, 0);
	lcd_waitcmd(1);
}


void lcd_gotoxy(u08 x, u08 y)
/* goto position (x,y) */
{
#if LCD_LINES==1
	lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x);
#endif
#if LCD_LINES==2
	if (y == 0)
		lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x);
	else
		lcd_command((1 << LCD_DDRAM) + LCD_START_LINE2 + x);
#endif
#if LCD_LINES==3
	if (y == 0)
		lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x);
	else if (y == 1)
		lcd_command((1 << LCD_DDRAM) + LCD_START_LINE2 + x);
	else if (y == 2)
		lcd_command((1 << LCD_DDRAM) + LCD_START_LINE3 + x);
#endif
#if LCD_LINES==4
	if (y == 0)
		lcd_command((1 << LCD_DDRAM) + LCD_START_LINE1 + x);
	else if (y == 1)
		lcd_command((1 << LCD_DDRAM) + LCD_START_LINE2 + x);
	else if (y == 2)
		lcd_command((1 << LCD_DDRAM) + LCD_START_LINE3 + x);
	else			/* y==3 */
		lcd_command((1 << LCD_DDRAM) + LCD_START_LINE4 + x);
#endif

}				/* lcd_gotoxy */



void lcd_putc(char c)
/* print character at current cursor position */
{
	lcd_waitcmd(0);
	lcd_write((unsigned char)c, 1);
	lcd_waitcmd(0);
}


void lcd_puts(const char *s)
/* print string on lcd  */
{
	while (*s) {
		lcd_putc(*s);
		s++;
	}

}


void lcd_init(u08 dispAttr)
/* initialize display and select type of cursor */
/* dispAttr: LCD_DISP_OFF, LCD_DISP_ON, LCD_DISP_ON_CURSOR, LCD_DISP_CURSOR_BLINK */
{
    /*------ Initialize lcd to 4 bit i/o mode -------*/

	lcd_data_port_out();	/* all data port bits as output */
	sbi(LCD_RS_DDR, LCD_RS_PIN);	/* RS pin as output */
	sbi(LCD_E_DDR, LCD_E_PIN);	/* E  pin as output */


	//lcd_delay_us(16000);	/* wait 16ms or more after power-on       */
    _delay_ms(160); 
	/* initial write to lcd is 8bit */
	lcd_out_high(LCD_FUNCTION_8BIT_1LINE);
	lcd_e_toggle();
	//lcd_delay_us(4000);		/* delay, busy flag can't be checked here */
    _delay_ms(4);
	lcd_out_high(LCD_FUNCTION_8BIT_1LINE);
	lcd_e_toggle();
	lcd_waitcmd(1);		/* delay, busy flag can't be checked here */

	lcd_out_high(LCD_FUNCTION_8BIT_1LINE);
	lcd_e_toggle();
	lcd_waitcmd(1);		/* delay, busy flag can't be checked here */

	lcd_out_high(LCD_FUNCTION_4BIT_1LINE);	/* set IO mode to 4bit */
	lcd_e_toggle();

	/* from now the lcd only accepts 4 bit I/O, we can use lcd_command() */
	lcd_command(LCD_FUNCTION_DEFAULT);	/* function set: display lines  */
	lcd_command(LCD_DISP_OFF);	/* display off                  */
	lcd_clrscr();		/* display clear                */
	lcd_command(LCD_MODE_DEFAULT);	/* set entry mode               */
	lcd_command(dispAttr);	/* display/cursor control       */
	lcd_waitcmd(1);
}
Схема в протеусе правильно вычерчена со всеми обозначениями.
Принцип работы схемы: контролер на ножке PIND5 порта PORTD5 считает импульсы генератора на LM311 и вычисляет частоту,
затем преобразует в Lx или Cx согласно выше представленным фомулам.
Цель статьи: Физика процессов измерения емкости, индуктивности, частоты микроконтроллерами.

Добавлено after 1 hour 32 minutes 54 seconds:
Да, забыл указать используемые макросы
#ifndef CONF_BOARD_H
#define CONF_BOARD_H

#ifndef _BV
#define _BV(bit) (1 << (bit))
#endif

#ifndef cbi
#define cbi(sfr, bit) (sfr &=~_BV(bit))
#endif

#ifndef sbi
#define sbi(sfr, bit) (sfr |= _BV(bit))
#endif

#define F_POT 80 //Это у нас потери на емкость монтажа

#endif // CONF_BOARD_H

Добавлено after 14 minutes 57 seconds:
Извините "ОЧЧЧЕПЯТКА!!!"
*контролер на ножке PIND5 порта PORTD
Вложения
FM.png
Схема
(54.13 КБ) 80 скачиваний
Ответить

Вернуться в «Цифровая техника»