Сначала код программы для 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);
}Код: Выделить всё
#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