Перейти к содержанию

Помогите новичку написать код на си для Avr


Dimas19904

Рекомендуемые сообщения

Пару месяцев учюсь программированию на языке Си для AVR.

Использую компилятор Code Vision AVR и мк ATmega8.

Хотел составить программу частотомера для мк ATmega8.

Немогу понять как напиисать участок программы отвечающий за динамическую индикацию.

Индикатор использую АЛС318

Напишите или помогите написать программу динамической индикации на Си для ATmega8.

Изменено пользователем Dimas19904
Ссылка на комментарий
Поделиться на другие сайты

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

1. кодируем символы, которые должны выводиться.

у меня на порте сегменты a..h соответствуют выводам порта 0..7. так удобней программировать, но не очень иногда разводку платы делать. не страшно :)

2. индицируем символ на данном разряде индикатора, для этого подключаем к питанию нужный разряд с помощью ключа, а на сегменты подаем код символа. Задерживаем на небольшое время, потом гасим этот разряд индикатора. Перебираем все разряды, попутно выводя на них соответствующие символы.

То, что должно быть на индикаторе, удобно занести в массив, где каждый элемент соответствует одному разряду. Главное будет, правильно выполнить разбиение числа на цифры (в нужном порядке), но это легко.

73 de R9FDJ ex. UB8FCG | QTH LO88AA, PM-03, Пермь | RCWC #1256

Ссылка на комментарий
Поделиться на другие сайты

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

1. кодируем символы, которые должны выводиться.

у меня на порте сегменты a..h соответствуют выводам порта 0..7. так удобней программировать, но не очень иногда разводку платы делать. не страшно :)

2. индицируем символ на данном разряде индикатора, для этого подключаем к питанию нужный разряд с помощью ключа, а на сегменты подаем код символа. Задерживаем на небольшое время, потом гасим этот разряд индикатора. Перебираем все разряды, попутно выводя на них соответствующие символы.

То, что должно быть на индикаторе, удобно занести в массив, где каждый элемент соответствует одному разряду. Главное будет, правильно выполнить разбиение числа на цифры (в нужном порядке), но это легко.

Благодарю за ответ.

Вообще несовсем все понятно.

А нет ли готовой программы в качестве примера?

Я уже третий день пытаюсь чтонибудь добиться, но безуспешно. Научился лишь выводить один знак на индикатор.

Ниже мой код может хотябы подскажеш как его сделать хотябы на 6-ть разрядов

//********************************************************

#include <mega8.h>

unsigned char led=4;

unsigned char S;

void main(void)

{

switch (led) {

case 0: (S=0b00111111); break;

case 1: (S=0b00000110); break;

case 2: (S=0b01011011); break;

case 3: (S=0b01001111); break;

case 4: (S=0b01100110); break;

case 5: (S=0b01101101); break;

case 6: (S=0b01111101); break;

case 7: (S=0b00000111); break;

case 8: (S=0b01111111); break;

case 9: (S=0b01101111); break;

}

DDRD=0xff;

PORTD=~S;

while(1);

}

//*********************************************

Заранее благодарю!!!

Ссылка на комментарий
Поделиться на другие сайты

Выбираем схему BMS для корректной работы литий-железофосфатных (LiFePO4) аккумуляторов

 Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ, также как и для других, очень важен контроль процесса заряда и разряда, а специализированных микросхем для этого вида аккумуляторов не так много. Инженеры КОМПЭЛ подготовили список имеющихся микросхем и возможных решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

#include <mega8.h>
unsigned char ind[6]={0,0,0,0,0,0};// отображаемые знаки

// кодировка символов
// параметр - символ
unsigned char symbol_2_bin(unsigned char symbol) 
{
  unsigned char result;

  switch (symbol) { 
  case 0: (result=0b00111111); break; 
  case 1: (result=0b00000110); break;
  case 2: (result=0b01011011); break;
  case 3: (result=0b01001111); break;
  case 4: (result=0b01100110); break;
  case 5: (result=0b01101101); break;
  case 6: (result=0b01111101); break;
  case 7: (result=0b00000111); break;
  case 8: (result=0b01111111); break;
  case 9: (result=0b01101111); break;
}
return result;
}

// вывод одного символа в данном разряде
// параметры - номер разряда, выводимый знак
void indicate_one{unsigned char digit, unsigned char symbol)
{
  char i;

  switch(digit)
  {
  case 0:PORTB=0x01;break;
  case 1:PORTB=0x02;break;
  case 2:PORTB=0x04;break;
  case 3:PORTB=0x08;break;
  case 4:PORTB=0x10;break;
  case 5:PORTB=0x20;break;
  }
  PORTD=~symbol_2_bin(symbol);

  i=0;
  while(i<50)i++;// задержка символа на индикаторе
}

// вывод на индикатор всего содержимого массива ind[]
void indicate_all(void)
{
  char i;
  for(i=0;i<=5;i++)
  {
  indicate_one(i,ind[i]);
  PORTB=0x00;// гасим индикатор
  PORTD=0xff;
  }
}

void main(void)
{
  DDRD=0xff;
  DDRB=0xff;

  while(1)
  {
   ...
  }
}

у меня лично эти три функции в отдельном файле .h и везде, где надо, идут уже шаблонно, еле вспомнил, что есть что здесь :)

а разбить число на цифры можно следующим образом (применительно к 6-разрядному индикатору, число тоже должно быть шестиразрядным.)

unsigned number;
unsigned char ind[6]={0,0,0,0,0,0};
unsigned char i;
...
i=0;
for(i=0;i<=5;i++)
{
  ind[i]=number%10;
  number/=10;
}

если исходное число вещественное, то стоит домножить его на 10 в какой-нить степени, чтоб получить шестизначную целую часть.

73 de R9FDJ ex. UB8FCG | QTH LO88AA, PM-03, Пермь | RCWC #1256

Ссылка на комментарий
Поделиться на другие сайты

//************************************************************************

#include <mega8.h>

unsigned char number,i,result,ind[6]={0,0,0,0,0,0}; // отображаемые знаки

// кодировка символов

// параметр - символ

unsigned char symbol_2_bin(unsigned char symbol)

{

switch (symbol) {

case 0: (result=0b00111111); break;

case 1: (result=0b00000110); break;

case 2: (result=0b01011011); break;

case 3: (result=0b01001111); break;

case 4: (result=0b01100110); break;

case 5: (result=0b01101101); break;

case 6: (result=0b01111101); break;

case 7: (result=0b00000111); break;

case 8: (result=0b01111111); break;

case 9: (result=0b01101111); break;

}

return result;

}

// вывод одного символа в данном разряде

// параметры - номер разряда, выводимый знак

void indicate_one(unsigned char digit, unsigned char symbol)

{

PORTD=~symbol_2_bin(symbol);

switch(digit)

{

case 0:PORTB=0x01;break;

case 1:PORTB=0x02;break;

case 2:PORTB=0x04;break;

case 3:PORTB=0x08;break;

case 4:PORTB=0x10;break;

case 5:PORTB=0x20;break;

}

i=0;

while(i<50)i++;// задержка символа на индикаторе

}

// вывод на индикатор всего содержимого массива ind[]

void indicate_all(void)

{

unsigned char i;

for(i=0;i<=5;i++)

{

//********************************************************

//Расбить число на цифры /* Как я понял код отвечающий за деление числа на цифры

ind=number%10; я должен был вставить сюда. */

number/=10;

//********************************************************

indicate_one(i,ind);

PORTB=0x00;// гасим индикатор

PORTD=0xff;

}

}

void main(void)

{

DDRD=0xff;

DDRB=0xff;

while(1)

{

number=0;

indicate_all();

}

}

//**********************************************************************************************************

За программу благодарю. С самой программой разобрался за исключением участка отвечающего за деление числа на цифры.

Проверял на железе если number = значение имеющее более одного знака на индикаторе загараются все знаки. Если что не так

прошу исправить.

Ссылка на комментарий
Поделиться на другие сайты

а, забыл написать... разбивать на цифры надо где-нибудь перед индикацией всего сразу, не в функции.

например:

...
while(1)
{
...
number=123456;
// здесь разбивка на цифры
for(i=0;i<=5;i++)
{
  ind[i]=number%10;
  number/=10;
}
// здесь индикация
indicate_all();
}

73 de R9FDJ ex. UB8FCG | QTH LO88AA, PM-03, Пермь | RCWC #1256

Ссылка на комментарий
Поделиться на другие сайты

//*****************************************************************************************

#include <mega8.h>

unsigned char ind[6]={0,0,0,0,0,0};// отображаемые знаки

unsigned number;

unsigned char i,n;

// кодировка символов

// параметр - символ

unsigned char symbol_2_bin(unsigned char symbol)

{

unsigned char result;

switch (symbol) {

case 0: (result=0b00111111); break;

case 1: (result=0b00000110); break;

case 2: (result=0b01011011); break;

case 3: (result=0b01001111); break;

case 4: (result=0b01100110); break;

case 5: (result=0b01101101); break;

case 6: (result=0b01111101); break;

case 7: (result=0b00000111); break;

case 8: (result=0b01111111); break;

case 9: (result=0b01101111); break;

}

return result;

}

// вывод одного символа в данном разряде

// параметры - номер разряда, выводимый знак

void indicate_one(unsigned char digit, unsigned char symbol)

{

PORTD=~symbol_2_bin(symbol);

switch(digit)

{

case 0:PORTB=0x01;break;

case 1:PORTB=0x02;break;

case 2:PORTB=0x04;break;

case 3:PORTB=0x08;break;

case 4:PORTB=0x10;break;

case 5:PORTB=0x20;break;

}

n=0;

while(n<50)n++;// задержка символа на индикаторе

}

// вывод на индикатор всего содержимого массива ind[]

void indicate_all(void)

{

for(i=0;i<=5;i++)

{

indicate_one(i,ind);

PORTB=0x00;// гасим индикатор

PORTD=0xff;

}

}

void main(void)

{

DDRD=0xff;

DDRB=0xff;

while(1)

{

number=12345;

// здесь разбивка на цифры

for(i=0;i<=5;i++)

{

ind=number%10;

number/=10;

}

// здесь индикация

indicate_all();

}

}

//********************************************************************************************

да теперь программа работает как надо и пожалуй последний вопрос:

Как управлять точками например если я подключу переключатели к порту С.

Заранее благодарен!!!

Изменено пользователем Dimas19904
Ссылка на комментарий
Поделиться на другие сайты

а вот с точками я сам понять не могу толком... у меня индикаторы на порте D висят, точка подключена на PORTD7, при индикации в нужном разряде засылаю в бит значение.

здесь у меня вариант для фиксированного положения точки во 2 разряде

void indicate_one(unsigned char digit, unsigned char symbol)
{

PORTD=~symbol_2_bin(symbol);
switch(digit)
{
case 0:PORTB=0x01;break;
case 1:PORTB=0x02;break;
case 2:PORTB=0x04;break;
case 3:PORTB=0x08;break;
case 4:PORTB=0x10;break;
case 5:PORTB=0x20;break;
}

if(digit==1)PORTD=(0<<(7));

n=0;
while(n<50)n++;// задержка символа на индикаторе
}

конкретно, не могу сообразить, что за переключатели на порте C :) что-то сегодня моск не туда работает :)

73 de R9FDJ ex. UB8FCG | QTH LO88AA, PM-03, Пермь | RCWC #1256

Ссылка на комментарий
Поделиться на другие сайты

С точками я пока решил отложить. Как я писал выше я хочу cделать частотомер. Я переделал в динамической индикации

выбор разряда на порт С, а выбор сегментов индикаторов на порт В, так как мне нужно использовать внешнее прерывание (INT0).

Мне надо чтобы мк считал в течение 20 миллисекунд на INT0 колличестов импульсов и присваивал полученный

результат number. Что-то до меня недоходит как это сделать.

Ссылка на комментарий
Поделиться на другие сайты

unsigned int i=0, number=0;

// External Interrupt 0

interrupt [EXT_INT0] void ext_int0_isr(void)

{

i++;

}

// Timer0 interrupt (можно другой таймер использовать)

interrupt [TIM0_OVF] void timer0_ovf_isr(void)

{ // Таймер настраиваешь на 20 ms

number=i;

i=0;

TCCR0=0x00;

}

Примерно так. Извини, если коротко написал просто времени нет...

Изменено пользователем IGRISE
Ссылка на комментарий
Поделиться на другие сайты

Я подключил к порту кнопку. Мне надо что бы при однократном нажатии на кнопку на порте устанавливалась 1, а при следующем нажатии ноль. Что то наподобии тригера. Можно ли это сделать без использования прерывания? и если

да то как?

Заранее благодарен!!!

Изменено пользователем Dimas19904
Ссылка на комментарий
Поделиться на другие сайты

Dimas19904, чем же тебе так прерывания, то не нравятся??? Без прерывания конечно можно...

Во первых их у ATmega8 всего два, а во вторых для меня проще написать программу без использования прерывания.

Незнаю может быть я и неправ.

А как сделать это без прерывания? Может кто написать программу?

Изменено пользователем Dimas19904
Ссылка на комментарий
Поделиться на другие сайты

Ну я тебе так, на словах пока разьясню:

Ты наверно имел ввиду без прерывания от INT0 и INT1, раз ты указал что их всего два...

Да написать программу без прерывания можно, но только мало кто так делают, если у тебя МК не занят другими задачами то используй просто задержки delay_ms(); delay_us();

Ну вот например делаешь так:

Считываешь состояние порта: save_first = PINX.X;

Ждешь 20 милли секунд: delay_ms(20);

Считываешь состояние порта: save_final = PINX.X;

Сравниваешь эти два значения, для подаления "дребезга контактов": if ((!f_new_key)&(save_first==save_final)) f_new_key=1; // получили новое значение от вывода, теперь можно использовать save_first или save_final для управления программой... если хочешь получить состояние кнопки тебе нужно обнулить флаг f_new_key=1;

Ждешь 20 милли секунд: delay_ms(20);

И все это зацикливаешь...

Только ты сам понимаешь, что обычно МК не только считывает состояние кнопки, но и еще что-то делает, поэтому использование функций delay_ms(); delay_us(); несколько замедлит выполнение программы, вместо того, чтобы МК что-то выполнял, он будет тупо сидеть в этих функциях и ждать, поэтому без прерывания от какого-нибудь таймера никак не обойтись... Удачи... :)

Dimas19904 ответил: для меня проще написать программу без использования прерывания

Можешь не использовать прерывания, а просто считывать флаг состояния прерывания, но тогда тебе придется принудительно после чтения обнулять эти флаги... Сразу оговорюсь, я так никогда не делал, но это конечно не озночает, что другие так не делали, попробуй... :)

Ссылка на комментарий
Поделиться на другие сайты

Да, я имел ввиду внешние прерывания INT0, INT1.

Только ты сам понимаешь, что обычно МК не только считывает состояние кнопки, но и еще что-то делает, поэтому использование функций delay_ms(); delay_us(); несколько замедлит выполнение программы, вместо того, чтобы МК что-то выполнял, он будет тупо сидеть в этих функциях и ждать, поэтому без прерывания от какого-нибудь таймера никак не обойтись... Удачи...

Спасибо, теперь я понял, что лучше использовать прерывания чем искать способ написания программы без использования прерываний.

Свободное внешнее прывание у меня осталось. Небуду усложнять себе жизнь, а пожалуй использую его для подключения кнопки

В дальнейшем я постараюсь разобраться с прерываниями получше!!!

Еще у меня такой вопрос: Мне надо подключить к порту матрицу из кнопок 4х4 тоесть 16 кнопок. Мне надо программу которая опрашивала бы состояние кнопок и присваивала результат опроса како-нибудь переменной.

Заранее благодарен.

Ссылка на комментарий
Поделиться на другие сайты

Ну вот я набросал примерный код, а так можно посмотреть на сайте Atmel, там много примеров даже такой есть какой ты просишь

void timer0_init()
{
// Используется для клавиатуры
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 15,625 kHz
// Mode: CTC top=OCR0
// OC0 output: Disconnected
TCCR0=0x00;
TCNT0=0x00;
OCR0=0xff;  // Происходит прерывание каждые 16,32 ms
}

interrupt [TIM0_COMP] void timer0_comp_isr(void)
{
/* Опрос клавиатуры (Клавиатура 4x4 подключена к порту X) */
DDRX=0xf0;	
PORTX=0x0f;  
key=PINX;  
DDRX=0x0f;   
PORTX=0xf0;  
key+=PINX;
key //это переменная которая содержит, код нажатой клавиши
}

Надеюсь пебе все понятно... Потому что я до Вторника сюда не буду приходить...

IGRISE уехал на отдых... :-)

Ссылка на комментарий
Поделиться на другие сайты

Есть еще такой вариант динамической индикации. Только сегодня написал. На железе пока не пробовал, пока только на протеусе.

//********************************************************************************************

#include <mega8.h> //0 1 2 3 4 5 6 7 8 9

flash unsigned char ind[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

unsigned char indt[6]={0,0,0,0,0,0};

unsigned char n,k,i,result;

unsigned long number;

void main(void) {

DDRC=0xff;

DDRB=0xff;

while(1) {

number=123456;

for(i=0;i<=5;i++)

{

indt=number%10;

number/=10;

}

for (i=0;i<=5;i++) {

n=indt;

PORTB=~ind[n];

switch(i) {

case 0: result=1; break;

case 1: result=2; break;

case 2: result=4; break;

case 3: result=8; break;

case 4: result=16; break;

case 5: result=32; break;

}

PORTC=result;

k=0;

while(k<50)k++;

PORTC=0x00;

PORTB=0xff;

} //for

} //while

} //main

//******************************************************************************************

Ссылка на комментарий
Поделиться на другие сайты

Меня знакомый парень попросил написать ему программу на си для ATmega8

Вот собственно:

/**********************************************************************************************

#include <mega8.h>

#include <delay.h>

interrupt[EXT_INT0] void ext_int0_isr(void) { //сюда программа попадет при "встрече припятствия"

PORTD.0=0;

PORTD.1=0;

PORTD.4=0;

delay_ms(300); //пауза для остановки машины перед движением назад

PORTD.5=1;

PORTD.0=1;

delay_ms(3000);

PORTD.0=0;

PORTD.5=0;

delay_ms(1000);

}

void port_init() {

#asm("cli") //запретить прерывания во время паузы

DDRD= 0x73;

GICR |=0x40; // INT0 вкл, INT1 выкл

MCUCR=0x0A;

GIFR=0x40;

ACSR=0x80; //Аналоговый компаратор выключен (для уменьшения энергопотребления)

SFIOR=0x00;

} //port_init

void main(void) {

port_init(); //установка состояний портов, прерывания запрещены

delay_ms(2000); //Задержка 5сек

#asm("sei") //по окончанию паузы после включения разрешить прерывания

//*************************************************************************

//Начать движение с первой скоростью ****************************************

PORTD.0=1; // Включить двигатель

delay_ms(3000); //установка времени движения с первой скоростью

PORTD.0=0; // Выключить двигатель

//*************************************************************************

//Начать движение со второй скоростью ****************************************

PORTD.1=1; // Включить двигатель

delay_ms(3000); //установка времени движения со второй скоростью

PORTD.1=0; // Выключить двигатель

//*************************************************************************

//Начать движение с третьей скоростью ****************************************

while(1) { //Бесконечный цикл

PORTD.4=1; // Включить двигатель

delay_ms(3000); //установка времени движения с третьей скоростью

//*************************************************************************

} //while

} //main

/********************************** **************************************************************

Вот мой вопрос:

После того как все условия в прерывание INT0 будут выполнены мне надо что-бы программа началась выполняться

с вот этого участка:

/********************************************************************************

//*************************************************************************

//Начать движение с первой скоростью ****************************************

PORTD.0=1; // Включить двигатель

delay_ms(3000); //установка времени движения с первой скоростью

PORTD.0=0; // Выключить двигатель

//*************************************************************************

//Начать движение со второй скоростью ****************************************

PORTD.1=1; // Включить двигатель

delay_ms(3000); //установка времени движения со второй скоростью

PORTD.1=0; // Выключить двигатель

//*************************************************************************

//Начать движение с третьей скоростью ****************************************

while(1) { //Бесконечный цикл

PORTD.4=1; // Включить двигатель

delay_ms(3000); //установка времени движения с третьей скоростью

//*************************************************************************

} //while

} //main

/**********************************************************************************

Как мне это сделать ??? Плизззззззз, кто-нибудь подскажите, очень надо!!!!

Заранее благодарен!!!!!!!!!!!!!!!!!!!!!!

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
  • Сообщения

    • @Gomerchik а вы контролировали как меняется уровень сигнала на А1 ардуины?
    • Спасибо за совет. Автором данного проекта я не являюсь, мне нужно было воссоздать уличный датчик для метеостанции взамен пропавшего(( Из разного найденного в интернете этот проект работает с моей станцией Орегон (спасибо автору). В понедельник попробую последовать Вашему совету. Но все равно куча непоняток  как блин это работает)) Если дело в неправильной отправки команды, то как на это влияет подключение датчика температуры? Если совсем не подключать таймер, то передача идет один раз (как и прописано в программе), станция принимает и отображает, но минут через сколько-то естественно станция уже ни чего не показывает, но с таймером питание полностью не пропадает с ардуинки, но передача сигнала каким-то образом работает по таймеру.  В моем понимании данная команда подается один раз потому, что таймер должен отключать питание МК после передачи сигнала и каждые 43 сек снова подавать питание (так того требует станция).  Ардуино передает показания температуры отключается полностью и 43 секунды мк не работает.  Сейчас у меня питание пока сделано на подпитке от солнечной батареи, но пару пасмурных дней и аккумулятор съедается до отключения(
    • thickman Так и сделаю. Вытащу из бу БП.  Буду знать, как отличить. Благодарю. Заменил транзисторы на IRFB20N50K. Картина стала, совсем другой.  Похоже трудность не в драйвере, на момент подвозбуда, переходные процессы, в нем, завершены. Увеличил затворные резисторы до 50ом, стало немного лучше.  Не понятно, почему верхний ключ греется несколько сильнее. Возможно, стоит посмотреть ток в коллекторе.  Снабберные емкости временно удалил, изменений не произошло.  Замена ТГР на другой, на кольце MSTN-16A-TH, так же, результата не принесла.   irfb20n50k.pdf
    • А что нить из ассортимента активных щупов производства СССР..))
    • Типа такого: https://aliexpress.ru/item/2044864227.html?sku_id=58855020183
×
×
  • Создать...