Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Изменение текста программы при смене компилятора и чипа
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Страницы: 1, 2, 3, 4, 5, 6, 7
RW6MKA
Привет всем. rolleyes.gif
Есть исходник программы написаный в IAR C v.3.10C для AT90S2313P, но такого камня уже не достать поэтому нужно переписать исходник для ATTINY2313V-10PU. Проблема в том,что IAR C v.3.10C триал или ломаная без библиотек и многого другого,поэтому изменять текст придётся в AVR Studio,но некоторые функции,как я понимаю,свойственны только IAR C v.3.10C(в частности h-файлы типа inavr.h и др.) Вообщем HELP!!! help.gif
Проще говоря нужно чтобы прога работала и компилировалась в AVR Studio или Code Vision AVR под камень ATTINY2313V-10PU. Вот сам исходник(чёт не получается файлом выложить)
/*
Компилировать IAR C v.3.10C
*/
#include <2313.h>
#include <inavr.h>

//#define DEBUG 1

// Подручные макросы
#define SetBit(address,bit) (address|=(1<<bit))
#define ClrBit(address,bit) (address&=~(1<<bit))
#define InvBit(address,bit) (address^=(1<<bit))
#define BitOn(address,bit) (address&(1<<bit))
#define BitOff(address,bit) (!(address&(1<<bit)))
#define NOP __no_operation()
#define IE __enable_interrupt()
#define DI __disable_interrupt()

#define DEBOUNCE 300
#define RUN 6 // Управление реле хода
#define REV 7 // Управление реле реверса
#define PRESC 2 // Прескалер таймера 0 (CLK/8)
#define AIN0 0
#define AIN1 1
#define T 7
#define SUM 50
#define YES 1
#define NO 0
#define REVPAUSE 800

typedef enum {Idle, RotL, RotR, LStop, RStop} State;


// Определения собственных типов данных
typedef unsigned char byte;
typedef unsigned int word;
typedef unsigned long ulong;

// Объявления прототипов функций
#ifdef DEBUG
void sb(byte data);
void phex(byte ch);
#define CRLF sb(13); sb(10)
#endif

byte GetKey(void);
byte KbdRotate(byte m);
byte KbdTest(void);
void ShiftReg(void);
void ShiftOne(byte r);
void RegClk(void);
void Strobe_1(void);
void Strobe_2(void);
void delayms (unsigned count);
unsigned getcount(void);
void RotCW(void);
void RotCCW(void);
void Stop(void);
word measure(void);
byte gp(void);
void Convert(byte data);
void Alarm(void);


__eeprom word dummy[8]= {0,0,0,0,0,0,0,0};
__eeprom State ee_stat;
__eeprom byte ee_angle;

// Таблица перевода количества импульсов, соответствующих входному
// напряжению в номер группы и номер светодиода в группе.
__flash byte LedPos[] = {
0x00,0x01,0x01,0x02,0x02,0x02,0x03,0x03,0x04,0x04,0x04,0x05,0x05,0x06,0x06,0x06,
0x07,0x07,
0x10,0x10,0x10,0x11,0x11,0x12,0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15,0x15,0x16,
0x16,0x17,
0x17,0x17,0x20,0x20,0x21,0x21,0x21,0x22,0x22,0x23,0x23,0x23,0x24,0x24,0x25,0x25,
0x26,0x26,
0x26,0x27,0x27,0x30,0x30,0x30,0x31,0x31,0x32,0x32,0x32,0x33,0x33,0x34,0x34,0x35,
0x35,0x35,
0x36,0x36,0x37,0x37,0x37,0x40,0x40,0x41,0x41,0x41,0x42,0x42,0x43,0x43,0x43,0x44,
0x44,0x45,
0x45,0x46,0x46,0x46,0x47,0x47,0x50,0x50,0x50,0x51,0x51,0x52,0x52,0x52,0x53,0x53,
0x54,0x54,
0x54,0x55,0x55,0x56,0x56,0x57};

__flash byte Mask[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

// Определение переменных программы
volatile word SysmS;
byte Regs[2];
byte Btn;
byte cnt;
volatile byte TH;
State Status;
byte Merge;
byte Angle;

// Начало основного модуля программы
__C_task void main(void){

// Настройка последовательного порта. Для настройки.
#ifdef DEBUG
UBRR = 25;
SetBit(UCR,TXEN);
#endif
Regs[1]=Regs[0]=0;
DDRD=0x71; PORTD=0x0E; // Настройка портов ввода/вывода
KbdRotate(0xFF); // Очистка регистра кнопок
ShiftReg(); // Очистка сдвигового регистра
// Настройка системного таймера на прерывания раз в 1 мсек
TCCR1B=0x0A;
OCR1=500;
TCNT1=0;
SetBit(TIMSK,OCIE1A);
SetBit(TIMSK,TOIE0);
ClrBit(DDRB,T); // Выключить транзистор
SetBit(DDRB,AIN0); // Разрядить конденсатор
delayms(1);
IE; // Разрешить глобальные прерывания
Merge = NO;
Status = ee_stat;
if ((Status==RotL) || (Status==RotR)) Alarm();
else Convert(Angle = ee_angle);
ee_stat = Status;

// ---------------------------------------------------------------
// Главная петля программы
while(1){
if ((Status==RotL)||(Status==RotR)){
Angle = gp();
Convert(Angle);
if (((Angle == 0x00)&&(Status==RotL)) || ((Angle == 0x57)&&(Status==RotR))){
Merge = YES;
Stop();
}
}
cnt = 0;
switch(Btn=GetKey()){
case 0x04: RotCW(); break;
case 0x08: Stop(); break;
case 0x10: RotCCW(); break;
}
}
}

void Alarm(void){
// Прокрутка трех кругов
byte c,i,j;
for (c=0; c!=3; c++)
for (j=0; j!=6; j++)
for (i=0; i!=8; i++){
Convert(i + (j<<4));
delayms(25);
}
Regs[0] = 0xFF;
Regs[1] = 0x00;
ShiftReg();
Status = Idle;
}

byte gp(void){
// Накопление и округление
word m = 0; byte i = SUM;
while(i--) m += measure();
i = m / SUM;
return((LedPos[i-20] & 0x77));
}

// Применение компаратора при измерении аналоговых величин.
word measure(void){
ClrBit(DDRB,AIN0); // Перевести в Z-состояние
TCNT0 = TH = 0; // Очистить счетчик-накопитель
TCCR0 = PRESC; // Включить Таймер 0
SetBit(DDRB,T); // Включить транзистор
while(BitOff(ACSR,ACO)); // Ждать изменения состояния компаратора
TCCR0 = 0; // Выключить Таймер 0
ClrBit(DDRB,T); // Выключить транзистор
SetBit(DDRB,AIN0); // Разрядить конденсатор
delayms(2); // Время для разряда
return(TH<<8 | TCNT0); // Возвращаем результат замера времени
}

#pragma vector = TIMER0_OVF0_vect
// Обработчик прерывания системного таймера
// Периодичность прерывания = 1 мсек
__interrupt void MeasureTick(void){
TH++;
}

void RotCW(void){
// Вращение по часовой стрелке
if (Status == RStop) return;
Merge = NO;
if (Status == RotL){
Stop();
delayms(REVPAUSE);
}
ClrBit(Regs[1],REV); // Выключить реле реверса
SetBit(Regs[1],RUN); // Включить реле хода
ShiftReg(); // Вывести в регистр
delayms(DEBOUNCE);
ee_stat = Status = RotR;
}

void RotCCW(void){
// Вращение против часовой стрелки
// Аналогично предыдущей функции
if (Status == LStop) return;
Merge = NO;
if (Status == RotR){
Stop();
delayms(REVPAUSE);
}
SetBit(Regs[1],REV); // но реле реверса включить
SetBit(Regs[1],RUN);
ShiftReg();
delayms(DEBOUNCE);
ee_stat = Status = RotL;
}

void Stop(void){
// Останов вращения
if ((Status==RotR)||(Status==RotL)){
ClrBit(Regs[1],REV);
ClrBit(Regs[1],RUN);
ShiftReg();
switch (Merge){
case YES: { if (Status==RotR)
Status = RStop; else
Status = LStop; break;}
case NO : Status = Idle; break;
}
Merge = NO;
ee_stat = Status;
ee_angle = Angle;
//CRLF; sb('S');sb('=');phex(Status);sb(' '); CRLF;
}
}

void Convert(byte data){
byte led, group;
static byte old;
if (data != old){
old = data;
led = data & 0x0F;
group = (data & 0x70)>>4;
Regs[0] = ~Mask[led];
Regs[1] &= 0xC0;
Regs[1] |= Mask[group];
ShiftReg();
}
}

void ShiftReg(void){
// Загрузка сдвигового регистра
ShiftOne(Regs[1]);
ShiftOne(Regs[0]);
Strobe_1();
}
void ShiftOne(byte r){
// Загрузка одного байта в регистр
char i=8;
while(i--){
if(!(r & 0x80)) ClrBit(PORTD,5); else SetBit(PORTD,5);
RegClk(); r <<=1;
}
}

byte GetKey(void){
// Сканирование кнопок с возвратом кода нажатой
byte Mask, temp = 0;
Mask = 0x3E; temp |= KbdRotate(Mask);
Mask = 0x3D; temp |= KbdRotate(Mask);
Mask = 0x3B; temp |= KbdRotate(Mask);
Mask = 0x37; temp |= KbdRotate(Mask);
Mask = 0x2F; temp |= KbdRotate(Mask);
Mask = 0x1F; temp |= KbdRotate(Mask);
return(temp & 0x3F);
}

byte KbdRotate(byte m){
// Вспомогательная функция для опроса кнопок
byte i=6, n = m;
while (i--){
if(!(m & 0x20)) ClrBit(PORTD,5); else SetBit(PORTD,5);
RegClk(); m <<=1;
}
Strobe_2();
if (BitOff(PIND,3)) return(~n);
return(0);
}

void RegClk(void){
// Формирование импульса тактировки регистра
SetBit(PORTD,4); ClrBit(PORTD,4);
}

void Strobe_1(void){
// Формирование строба первого регистра
SetBit(PORTD,6); ClrBit(PORTD,6);
}

void Strobe_2(void){
// Формирование строба второго регистра
SetBit(PORTD,0); ClrBit(PORTD,0);
}


#pragma vector = TIMER1_COMP1_vect
// Обработчик прерывания системного таймера
__interrupt void DelayTick(void){
++SysmS;
}

unsigned getcount(void){
// Возвращает значение системного счетчика (мсек)
unsigned t;
IE; t = SysmS; DI;
return (t);
}

void delayms (unsigned count){
// Функция формирования задержки в мсек
unsigned t = getcount();
while ((getcount() - t) <= count){}
}

#ifdef DEBUG
void phex(byte ch){
// Выводит байт в шестнадцатиричном формате
byte n;
n = (ch >> 4) + 0x30;
if (n > 0x39) n += 7;
sb(n);
n = (ch & 0x0F) + 0x30;
if (n > 0x39) n += 7;
sb(n);
}

void sb(byte data){
// Передача одного байта по последовательному порту
while ( !(USR & (1<<UDRE)) );
UDR = data;
}
#endif
sigmaN
Цитата
нужно чтобы прога работала и компилировалась в AVR Studio или Code Vision AVR под камень ATTINY2313V-10PU. Вот сам исходник(чёт не получается файлом выложить)
Ну а так вообще чего там...обычное портирование... если не ставить целью перелазить на GNU(WinAVR) то будет не так уж и сложно. Кода не много...Работы, соответственно, тоже )
Ну вы же не ждете, что я сейчас полезу в даташиты и буду сравнивать названия регистров и номера байтов одного и другого контроллера и указывать Вам на конкретные изменения в коде?
Эту работу Вам придётся проделать самостоятельно.
Перелезть с IAR на GNU будет ещё чуть более хлопотно, т.к. слыхал, что IAR имеет(впрочем как и все компиляторы) немного своих специфичных примочек(не знаю используются ли они в вашем коде)..
RW6MKA
Кода действительно немного и переделать эту программку тоже, я думаю, не составит большого труда опытному программеру,но...ОПЫТНОМУ! wink.gif Я в этом деле чайник и поэтому и прошу помощи у клуба знатоков. help.gif
Есть,как мне кажется, два пути решения этой проблемы:1-выставить фьюзы для tyni2313 и прошить его прошивкой для 90s2313,по идее это должно сработать.2(более длинный путь)-переделка исходника и его компиляция в CodeVisionAVR под tyni2313.Это более трудный путь,но более предпочтительный.Если бы кто взялся помоч в этом хотя бы советами и комментариями к исходнику я был бы очень признателен. a14.gif Простая вставка текста в проект CodeVisionAVR даёт кучу ошибок начиная с заголовочных файлов <2313.h> <inavr.h>,которые видимо используются только в IAR,но если с первым понятно то чем заменить <inavr.h>вообще не понимаю и всё в таком духе... crying.gif Вообщем нужны коменты по строчкам какая что делает и совет как это написать в CodeVisionAVR help.gif
По этому адресу описание устройства http://www.ut1wpr.newmail.ru/DirAnt/dir.htm а схему устройства и файл исходника вкладываю.Нажмите для просмотра прикрепленного файла Нажмите для просмотра прикрепленного файла
sigmaN
Не волоку в специфике CodeVisionAVR, я от WinAWR и Атмеловской студии тащусь wink.gif

Лично я начал бы с разбора существующего исходника. Нужно добиться того, чтобы каждая строка была понятна вам. Что куда и зачем. Это должно быть в голове.

Как вариант, я бы таки поставил кряканый IAR и поглядел бы во все эти заголовки. А может быть даже компильнул бы из IARа данный исходник, а потом в симуляторе глянул бы что к чему(это поможет реально понять программу). Ну а дальше надо начинать портировать. Если вы будете понимать каждую строчку - это перестанет быть сложной задачей.
Ну а в WinAVR всё начинается с выбора правильного камня и частоты в свойствах проекта и инкуда
Код
#include <avr/io.h>
ну и привыкаем сразу к
Код
#include <stdint.h>
а также может пригодиться
Код
#include <util/delay.h>


И с этого момента вся переферия будет доступна вам!
Код
//конфигурируем пины, управляющие дисплеем как OUTPUT
    DDRB = (1 << 0) | (1 << 6) | (1 << 7);
    DDRD = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7);
    //порт С весь используется как OUTPUT(на нем строки и спикер)
    DDRC = 0xFF;
    /*
    * включаем pull-up резисторы на пинах с кнопками
    * внешних резисторов нет и кнопки иначе работать небудут
    */
    PORTD |= (1 << 2) | (1 << 3);
как-то так.....

Ну и даташит придётся полистать, а что делать что делать, кому щас легко? )

Блин, а программу маньяк какой-то писал))
Одно только
Код
Convert(Angle = ee_angle)
чего стоит )) Но ничего, заодно и Си подучите ))
RW6MKA
Цитата
Не волоку в специфике CodeVisionAVR, я от WinAWR и Атмеловской студии тащусь

Да я сам не волоку,но это чуть ли не едиственный компилятор по которому есть неплохие книги на русском blush.gif

Цитата
Лично я начал бы с разбора существующего исходника. Нужно добиться того, чтобы каждая строка была понятна вам. Что куда и зачем. Это должно быть в голове.

Вот и я хочу разобраться с кодом,хотя честно сказать в С полный чайник. smile3046.gif Есть и hex этого исходника сделаный в IAR т.е.залить его в чип и дело с концом,но автор не уверен что это рабочая версия программы(за давностью разработки файлы перепутались и мне скинул что нашел)и поэтому желательно сначала проверить её на работоспособность.

Наверно я всё таки не правильно подхожу к проблеме.Попытаюсь сформулировать свою просьбу по другому.1)Народ,скажите кто может проверить,это рабочая программа?2)Если выставить фьюзы на tiny2313 и прошить прошивкой с этой прогой(которая писалась напомню под 90s2313) будет ли tiny2313 работать правильно?Это что касается практической стороны вопроса(ну в самом деле отступать поздно,схема материализована и ждёт прошивки). rolleyes.gif В теории же хочется разобраться какой кусок программы за что отвечает и имеющихся в проге коментов для меня явно маловато,поскольку повторюсь чайник я в этом. Посему прошу, если найдётся добрая душа, согласная помочь страждущему новичку,то пусть вооружится терпением и маркером и пометит разными цветами куски проги отвечающие за:
1.включение реле2,реле1 т.е.вращение двигателя
2.индикацию
3.прекращение поворота дальше определённого положения датчика(кстати я так понимаю происходит сравнение падения напряжения на датчике с эталонным?)
4.занесения показаний индикации в память и чтение оттуда
и т.д.
И может кто подсказать где посмотреть готовые куски программ с реализацией схожих задачь?

sigmaN
Давайте разберемся какая у вас цель то?
1. Вам нужен просто рабочий девайс? Тогда реально один действенный выход: найти программера(практически любого программера, имющего опыт работы с микроконтроллерами) и он здесь разберется. Заплатите ему денег и все будут довольны. Тем более, что железо уже есть. А может заплатить тому человеку у которого взяли исходник?

2. Проект образовательный, вам надоело быть чайником и вы твёрдо решили разобраться и готовы потратить на это столько времени, сколько будет необходимо.
На этот вариант будет свой roadmap(предложу, если интересно) и вы всё сможете.

И поймите же наконец, ну не станет никто копаться в этом коде и что-то там выяснять и выделять цветами.
Тем более при такой постановке вопросоа. Вы по сути просите за вас выполнить работу.
На этом форуме большинство людей ценит своё время, у каждого есть свои проекты начиная от хобби и заканчивая халтурами...
Что-то реальное подсказать - всегда подскажут или направят, но работать придётся всё равно Вам.

Я просмотрел код по диагонали и мне он вообще не нравится! ИМХО тут хорошо бы заново сформулировать задачу и переписать всё по человечески.

И поймите, если времени нет и девайс реально нужен работающий - вы ничего не успеете и на много правильнее будет дать денег кому-нибудь.
RW6MKA
Цитата
1. Вам нужен просто рабочий девайс?

Да,мне нужен рабочий девайс и эту проблему я решу,не заморачивайтесь.

Цитата
Проект образовательный, вам надоело быть чайником и вы твёрдо решили разобраться и готовы потратить на это столько времени, сколько будет необходимо.
На этот вариант будет свой roadmap(предложу, если интересно) и вы всё сможете.

Да,скорее так,не люблю когда что то не понятно и буду рад любой помощи.Я бы с радостью написал программу заново,если бы знал как.Если вы согласитесь изредко просматривать куски моей проги и корректировать их,то буду премного благодарен,но это наверно лучше уже через личку,а эту тему наверно стоит прикрыть поскольку не несёт ничего полезного.
sigmaN
Насчёт лички не согласен )
Прокомментировать ваш код и ответить на конкретные вопросы - без проблем.

Недавно тут(в разделе начинающих) кому-то помогали ссылками и литературой по Си, найдите топик, скачайте и читайте.
В общем начинать неплохо с Кернигана и Ричи Язык Си 2е издание. Именно 2е, не 1е!
А также в Сети найдете многго чего по AVR на русском.


Удачи!
RW6MKA
Спасибо,эта книга у меня есть её и читаю.Литературы действительно много.
Программу начну писать заново,схема таже,но задачи,я думаю лучше разбить на куски.
Сначала написать прогу по повороту при нажатии соответствующей кнопки вправо, влево, стоп.При этом если после поворота в одну сторону нажать не стоп а сразу поворот в другую сторону, то включение поворота должно происходить всё равно после остановки на 2с.
Потом нужно реализовать функцию остановки вращения при достижении датчиком определённого сопротивления при этом кнопка вращения в эту сторону должна блокироваться.
Потом добавить индикацию угла поворота датчика.
Потом запись последних показаний в память.Как такая последовательность?
sigmaN
Хорошо.
Вот с этого и начните.
Делаем пустой проект, инициализируем нужные порты как выход( RUN и REV на вашей схеме) нужные на вход(кстати где там кнопки то?).
Программа получится строк на 10 макс. Кнопки для начала можно опрашивать прямо в цикле типа вот так:
Код
//если нажата кнопка 2 - стоп
            if( !(PIND & 0x8) )
            {
              PORTB &= ~0x0С; //очистить биты 2 и 3 порта B. Таким образом двигатель останавливается
            }
Тут кнопка коротит порт на землю. Т.е. если кнопка нажата - соответствующий бит порта ставится в 0.
В этом примере мы проверяем бит 3 порта D микроконтроллера. Именно на этот пин подключена кнопка.
Ну а на B2 и B3 допустим подключены RUN и REV.
Соответственно, в обработчике другой кнопки(RUN) будет установка соответствующего бита порта B.

Подставьте свои значения из схемы и всё будет )
RW6MKA
Вот кусочек моих стараний smile3046.gif ,при компиляции ошибок нет,но в протеусе не работает,что не так?
Код
#include <tiny2313.h> //загрузка библиотеки ATtiny2313
#include <delay.h>    

void main(){
                 // инициализация порта D
                  //PD1-2 func=out,state=0
                  //PD4-6 func=in,state=P
   PORTD=0x70;    //установка битов порта D в 0 или 1
   DDRD=0x06;     //установка порта D на in или out
   ACSR=0x80;     //настройки аналогового компаратора
  while (PIND.6==0){      //если кнопка S0(см.схему) нажата
     PORTD.2=1;           //включить поворот вправо(RUN)
    }                     //цикл выполняется пока действительно условие
  while (PIND.4==0){      //если кнопка S2 нажата
     PORTD.1=1;           //включить поворот влево(REV)
    }
}
sigmaN
Ну конечно не будет работать.
Всё дело в том, что Ваша программа пробегает отдин раз(за доли секунды) и выходит из функции main.

Вам нужно организовать бесконечный цикл и уже в нем проверять условие нажатия кнопок и выдавать соответствующие сигналы.
Код
while (1)
{
  if (PIND.6==0)
  {      //если кнопка S0(см.схему) нажата
     PORTD.2=1;           //включить поворот вправо(RUN)
  }                     //цикл выполняется пока действительно условие
  if (PIND.4==0)
  {      //если кнопка S2 нажата
     PORTD.1=1;           //включить поворот влево(REV)
  }
}


Кстати, судя по схеме, у вас RUN 1/0 задаёт работает ли двигатель в принципе(старт/стоп), а вот REV 1/0 задаёт направление вращения.

P.S. инициализацию
PORTD=0x70; //установка битов порта D в 0 или 1
DDRD=0x06; //установка порта D на in или out
ACSR=0x80; //настройки аналогового компаратора
не проверял. Оставлю проверку битов Вам в качестве домашнего задания ))

P.P.S. Это только мне кажется, что там на кнопках диоды не в ту сторону стоят?
Дело в том, что из Вашей программы следует, что нажатие кнопки приводит к установке низкого уровня на порте(проверка на == 0).
Т.е. кнопка должна цепляться на общий провод, а высокий уровень при размыкании контактов кнопки, по идее устанавливается за счёт внутренних подтяжек(pull-up резисторов) контроллера.
Кстати не забудьте, что их можно случайно отключить и вообще я бы поставил ещё внешние для увеличения помехозащищенности.
Таким образом, если кнопка нажата - ток через pull-up резистор вытекает из микроконтроллера и уходит в общий провод.
Однако диоды установлены неправильно и при таком сценарии окажутся запертыми и ток не потечет. А значит лог. 0 на ноге контроллера установлен не будет.
RW6MKA
Цитата
Ну конечно не будет работать.
Всё дело в том, что Ваша программа пробегает отдин раз(за доли секунды) и выходит из функции main.

Я об этом думал,но никто не пишет о таких простых вещах,поэтому не нашел подтверждения своим мыслям.

Цитата
Кстати, судя по схеме, у вас RUN 1/0 задаёт работает ли двигатель в принципе(старт/стоп), а вот REV 1/0 задаёт направление вращения.

Нет,включается какое то одно реле и их переключение меняет полярность питания двигателя и соответственно направление его вращения.

Цитата
P.P.S. Это только мне кажется, что там на кнопках диоды не в ту сторону стоят?

Знаете,у меня подозрение что это типа матричной клавы(строка PD3,столбцы - PD4-6) и диоды включены правильно,но тогда сопротивление R3 должно быть 470Ом.Если это не так,то я тогда не понимаю назначение вывода RET?
На протеусе я моделировал без диодов кнопкой на землю(при включённых подтягивающих резисторах)
Кстати вы не пользуетесь протеусом?Если пользуетесь подскажите как поменять номинал VCC.

Цитата
Кстати, судя по схеме, у вас RUN 1/0 задаёт работает ли двигатель в принципе(старт/стоп), а вот REV 1/0 задаёт направление вращения.

Именно так,я сначала написал потом взглянул на схему,так что алгоритм работы поменяю на
Код
while(){
  
     while (PIND.6==0){    //если кнопка S0(см.схему) нажата
     PORTD.2=1;            //включить поворот (RUN)
     PORTD.1=0;            //реверс не включать
     }                     //цикл выполняется пока действительно условие
     while (PIND.4==0){    //если кнопка S2 нажата
     PORTD.2=1;            //включить поворот
     PORTD.1=1;            //включить реверс(REV)
     }
    
   }

}
так я думаю правильно?Вот я ещё слышал как то дребезг контактов кнопок компенсируют?Да,и думаю от кнопки стоп вообще отказаться(используя не фиксируемые кнопки при таком алгоритме "пока держишь-крутится" я думаю стоп лишняя функция)
sigmaN
Цитата
Цитата
Кстати, судя по схеме, у вас RUN 1/0 задаёт работает ли двигатель в принципе(старт/стоп), а вот REV 1/0 задаёт направление вращения.


Нет,включается какое то одно реле и их переключение меняет полярность питания двигателя и соответственно направление его вращения.
Ну я хоть и программер, но по схеме же видно, что нижние по схеме контакты - это RUN. Когда они замкнуты на двигатель - он вращается в направлении, которое определяется положением верхних контактов, а следовательно: уровнем на выводе REV.

Цитата
Знаете,у меня подозрение что это типа матричной клавы(строка PD3,столбцы - PD4-6) и диоды включены правильно,но тогда сопротивление R3 должно быть 470Ом.Если это не так,то я тогда не понимаю назначение вывода RET?
Как-то странно всё это....честное слово.... какой тут смысл во всех этих матрицах? В общем надо бы смотреть исходник тот оригинальный....

В протеусе там что-то типа Design->Power rails....кажется.В общем ищите Power rails. Сейчас протеус не установлен - точно сказать не смогу.


Цитата
Именно так,я сначала написал потом взглянул на схему,так что алгоритм работы поменяю на.....
Вы кажется игнорируете то, что я вам говорю.
Найдите 10 отличий между Вашим кодом и тем, что я привел в предыдущем сообщении.
Ну не нужны там while, там if же! А в главном цикле нужно while(1) !
1 в скобках означает истину. А while, как известно, исполняется пока значение в скобках истинно. В Си логический тип интерпретируется следующим образом: 0 - ложь; Не 0 - истина;
т.е. запись while(1) создаёт бесконечный цикл, в котором мы непрепывно проверяем нажатие кнопок и меняем состояние пинов RUN и REV.
Конечно, Ваши while (PIND.6==0){ тоже будут работать, но вообще if там более корректно.
RW6MKA
Цитата
Вы кажется игнорируете то, что я вам говорю.
Найдите 10 отличий между Вашим кодом и тем, что я привел в предыдущем сообщении.
Ну не нужны там while, там if же! А в главном цикле нужно while(1) !


Я видел что у вас выражено через оператор if,но честно говоря не понимаю разницы.И там и там проверяется условие и если оно правильно работает тело,а 1 я просто забыл написать,потом то исправил когда при компиляции получил ошибку.Сам код я так понимаю правильный?
Код
while(1){
  
     if (PIND.6==0){    //если кнопка S0(см.схему) нажата
     PORTD.2=1;            //включить поворот (RUN)
     PORTD.1=0;            //реверс не включать
     }                     //цикл выполняется пока действительно условие
     if (PIND.4==0){    //если кнопка S2 нажата
     PORTD.2=1;            //включить поворот
     PORTD.1=1;            //включить реверс(REV)
     }
    
   }

Теперь такой вопрос.Мне не понятна реализация измерения напряжения датчика угла поворота.Как это делается и где можно почитать об этом?
sigmaN
Цитата
Я видел что у вас выражено через оператор if,но честно говоря не понимаю разницы.И там и там проверяется условие и если оно правильно работает тело
Да, но тогда у Вас зациклится присвоение значения регистру PORTD и пока кнопка нажата - мы будем непрерывно присваивать, в то время как остальные операторы исполняться не будут.
Теперь представьте если у вас ниже в коде идет проверка состояния концевика(ну типа двигатель дошел до определенной точки - включить реверс), а тут вдруг кто-то нажал кнопку и держит - движок дойдет до упора, а может быть и сломает что-нибудь )) Ну это так, самый простой пример. Да и просто реально нет там необходимости в цикле. Ни малейшей. Но в вашем конкретном случае в таком виде как оно есть сейчас - работать конечно будет и с while.


Цитата
Мне не понятна реализация измерения напряжения датчика угла поворота.
Напряжение измеряется с помощью ADC(АЦП).


Советую не привыкать использовать стиль K&R в расстановке операторных скобок
вместо
if (PIND.4==0){
я рекомендовал бы писать
if (PIND.4==0)
{

позднее, при отладке вложенных условий вы непременно оцените преимущества такого стиля.
RW6MKA
Цитата
Да, но тогда у Вас зациклится присвоение значения регистру PORTD и пока кнопка нажата - мы будем непрерывно присваивать, в то время как остальные операторы исполняться не будут.

Вот теперь всё ясно!
Цитата
Напряжение измеряется с помощью ADC(АЦП).

???Если можно несколько подробнее(эх,пример бы посмотреть).Из исходника
Код
// Применение компаратора при измерении аналоговых величин.
word measure(void){
        ClrBit(DDRB,AIN0);                        // Перевести в Z-состояние
        TCNT0 = TH = 0;                                // Очистить счетчик-накопитель
        TCCR0 = PRESC;                                // Включить Таймер 0
        SetBit(DDRB,T);                                // Включить транзистор
        while(BitOff(ACSR,ACO));                // Ждать изменения состояния компаратора
        TCCR0 = 0;                                        // Выключить Таймер 0
        ClrBit(DDRB,T);                                // Выключить транзистор
        SetBit(DDRB,AIN0);                        // Разрядить конденсатор
        delayms(2);                                        // Время для разряда
        return(TH<<8 | TCNT0);                        // Возвращаем результат замера времени
}

я практически ничего не понял???

Цитата
я рекомендовал бы писать
if (PIND.4==0)
{

Я сначала так и писал(так нагляднее),но посмотрев примеры кодов решил писать как все.
Да,с настройкой портов ввода и вывода в исходнике я то же не пойму,на кнопках почему то выход а RUN REV как вход???
Код
DDRD=0x71; PORTD=0x0E;                        // Настройка портов ввода/вывода

видимо кнопки реализованы как то по другому
sigmaN
Цитата
Цитата
Напряжение измеряется с помощью ADC(АЦП).

???Если можно несколько подробнее(эх,пример бы посмотреть).Из исходника
Да да, в этом контроллере нет АЦП, поэтому применяется компаратор.
Измеряемое напряжение подаётся на один вход, а на другом входе имеем конденсатор С8 и транзистор Q1.
В базе транзистора присутствует достаточно большое сопротивление, что ограничивает ТОК коллектора таким образом, чтобы конденсатор заряжался не мгновенно, а с достаточной задержкой.
Т.е. если бы этот резистор был меньше - ток заряда конденсатора был бы больше и он заряжался бы ооочень быстро.
Компаратор позволяет заметить момент, когда напряжение на AIN0(а значит на обкладках конденсатора) становится больше AIN1.
Этого события мы и ожидаем в коде while(BitOff(ACSR,ACO)); // Ждать изменения состояния компаратора
По времени, за которое конденсатор разрядился на столько, чтобы сравниться с измеряемым напряжением мы и можем судить о величине измеряемого напряжения.
Думаю о конкретном значении можно говорить только после проведения калиборовки, подавая заранее известное значение напряжения и замечая, скольким тикам таймера оно соответствует.


Цитата
видимо кнопки реализованы как то по другому
очень интересно. Диоды то почему тогда стоят не в ту сторону?! Да при таком раскладе даже если там и выход - через диод то всё равно не пройдет ничё! Но может быть я чего-то не знаю и тут какая-то неведомая хитрость присутствует )
И тут даже в коде всё это явно накручено и высосано из пальца. Ну нет смысла для трёх кнопок так извращаться.
Рекомендую забить на это дело и сделать свои кнопки по простому.
И вообще, честно, код не очень то хорош. Я бы не рекомендовал особо сильно подражать такому подходу.
Я могу точно сказать, что программу, реализующую заявленный функционал можно написать на много более наглядно и просто. Что и рекомендую Вам сделать.
И кнопки я бы сделал всего две. Стоп это когда ничего не нажато. Ну и по часовой/против часовой - понятно.

Цитата
Для экономии ресурсов НП, (производителем заявлено гарантированных 100000 циклов записи/стирания) запись состояния производится только в моменты его изменения. А именно, в моменты начала вращения или после останова. В моменты останова в энергонезависимую память заносяться параметры последнего угла положения. При включении устройства управления эти данные будут извлечены из памяти и отображены "поджиганием" необходимого светодиода. Если же останов произошел по вине пропадания питания (в этом случае последним зафиксированным состоянием будет состояние вращения), то при включении МК проинформирует о недостоверности указания направления трехкратной быстрой прокруткой светящейся точки по всем светодиодам, и табло останется погашенным. При первой же команде на вращение зажжется светодиод, реально отображающий положение антенны.
ИМХО - хреновый подход. Не нужно там ничего записывать в EEPROM. Ведь достаточно при включении просто дёрнуть движком туда-сюда(причём на доли секунды) чтобы подать напряжение для измерения угла и засветить нужный светодиодегг ))
RW6MKA
Цитата
Измеряемое напряжение подаётся на один вход, а на другом входе имеем конденсатор С8 и транзистор Q1.

То есть если я правильно понял алгоритм следующий:включаем таймер для замера времени необходимого для изменения состояния компаратора - включаем транзистор - ждём пока конденсатор зарядится на уровень срабатывания компаратора - таймер выкл - транзистор выкл -кондёр разряжаем(для следущего заряда) - результат замера времени таймером отправляем для сравнения в
Код
// Таблица перевода количества импульсов, соответствующих входному
// напряжению в номер группы и номер светодиода в группе.
__flash byte LedPos[] =  {
         0x00,0x01,0x01,0x02,0x02,0x02,0x03,0x03,0x04,0x04,0x04,0x05,0x05,0x06,0x06,0x06,
0x07,0x07,
        0x10,0x10,0x10,0x11,0x11,0x12,0x12,0x12,0x13,0x13,0x14,0x14,0x15,0x15,0x15,
0x16,0x16,0x17,
        0x17,0x17,0x20,0x20,0x21,0x21,0x21,0x22,0x22,0x23,0x23,0x23,0x24,0x24,0x25,
0x25,0x26,0x26,
        0x26,0x27,0x27,0x30,0x30,0x30,0x31,0x31,0x32,0x32,0x32,0x33,0x33,0x34,0x34,
0x35,0x35,0x35,
        0x36,0x36,0x37,0x37,0x37,0x40,0x40,0x41,0x41,0x41,0x42,0x42,0x43,0x43,0x43,
0x44,0x44,0x45,
        0x45,0x46,0x46,0x46,0x47,0x47,0x50,0x50,0x50,0x51,0x51,0x52,0x52,0x52,0x53,
0x53,0x54,0x54,
        0x54,0x55,0x55,0x56,0x56,0x57};

__flash byte Mask[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

Кстати я думаю эту таблицу можно повзаимствовать из исходника,я думаю автор её составлял не наугад.Может кстати весь блок кода применения компаратора повзаимствовать?Только вот я не совсем с ним разобрался(но это видимо потому,что плохо знаю работу компаратора в МК)В частности загадка для меня
Код
#define ClrBit(address,bit) (address&=~(1<<bit))

&=~ что за сочетание??? & это порязрядное И или определение адреса?~ это поразрядное отрицание?(1<<bit) это умножение 1 на 2 в степени bit или это сдвиг 1 на bit влево?Не понимая этого я соответственно не понимаю
Код
ClrBit(DDRB,AIN0);

Вообщем масса вопросов.Кстати, что то не могу найти примеров, где компаратор использовался бы подобным образом,не подскажите где поискать?

Цитата
Рекомендую забить на это дело и сделать свои кнопки по простому.

Вот я так и сделаю.В принципе они как кнопки готовы вот только осталось ввести функцию концевиков,но для этого опять же нужно разобраться с компаратором.
Цитата
ИМХО - хреновый подход. Не нужно там ничего записывать в EEPROM. Ведь достаточно при включении просто дёрнуть движком туда-сюда(причём на доли секунды) чтобы подать напряжение для измерения угла и засветить нужный светодиодегг ))

Совершенно согласен.
sigmaN
Цитата
Кстати я думаю эту таблицу можно повзаимствовать из исходника,я думаю автор её составлял не наугад
Вы знаете, я ещё не смотрел как там увАжаемый афтар реализовал все эти светодиоды, но почему-то моё чутьё подсказывает, что вероятность черезжопной реализации там также высока. Поэтому опять же нужно смотреть и очень хорошо подумать...
В принципе можно и таблицу.. Вообще там всё зависит от схемы включения диодов. Там их просто довольно много и я подозреваю, что как раз таки они включены матрицей. 8*8=64.
Т.е. на те два регистра можно нацепить 64 диода.
И в принципе, если там задержка будет линейно зависеть от положения потенциометра - ничто не мешает использовать функцию, которая элементарно на ходу вычислит строку и диод в строке, который нужно засветить. Строки матрицы будут физически расположены по дуге. Все строки вместе составляют линию окружности.
А вот если время заряда кондера будет нелинейно зависеть от поворота ручки, то проще будет таблицей ибо для начинающего там уже будет заморочка с расчётом на ходу...

Цитата
&=~ что за сочетание??? & это порязрядное И или определение адреса?
Вопросы это хорошо! & здесь - поразрядное И.
Запись a &=b; эквивалентна a = a & b; таким образом имеем address&=~(1<<bit) эквивалентно address = address & ~(1<<bit);
И поскольку приоритет операции ~ выше, чем операции & - будет выполнено сначала то, что в скобках, потом к каждому биту результата будет применена операция НЕ, после этого выполняется оператор &.
Таким образом мы очистим бит номер bit переменной address. Только опять таки address тут немного некорректное имя, т.к. всё же параметром этого макроса является переменная, а не указатель.

Цитата
Кстати, что то не могу найти примеров, где компаратор использовался бы подобным образом,не подскажите где поискать?
Не знаю. А зачем? Ведь и так всё ясно. Главное знать как работает компаратор, а как его использовать - это дело разработчика ))
sigmaN
А ещё я тут подумал...
Светодиоды(сдвиговые регистры) надо цеплять к контроллеру по интерфейсу Universal Serial Interface – USI.
Тогда вся эта программная муть, формирующая клоки и выталкивающая данные в сдвиговые регистры будет заменена кодом конфигурации USI, а потом только регистр подгружай и прерывания лови. Сама передача и тактирование будут выполняться аппаратно.
Правда немного схему переделать придётся, чтобы регистры на нужных пинах оказались, но я думаю это не проблема.
RW6MKA
Цитата
Вы знаете, я ещё не смотрел как там увАжаемый афтар реализовал все эти светодиоды

Насколько я понял 6 групп по 8 светодиодов через регистры CD4094N от МК0 по последовательному порту.

Цитата
Запись a &=b; эквивалентна a = a & b; таким образом имеем address&=~(1<<bit) эквивалентно address = address & ~(1<<bit);
Вообщем понял,но конкретно видимо пока сложно для новичка в С. Насколько понял в скобках (1 сдвигаем влево на bit) - в полученом(например 011001 меняем наоборот 100110)проводим отрицание - address будет истина если address и полученное после отрицания тоже истинны?Бр-р-р.Нифига не понял.Нельзя это всё проще выразить?

Цитата
Не знаю. А зачем? Ведь и так всё ясно. Главное знать как работает компаратор, а как его использовать - это дело разработчика ))

Да мне посмотреть примеры кодов,кто как пишет.Как запускают таймер,как отключают,как использовать результат замера времени и т.д.Я ж всё таки начинающий, мне легче когда есть посмотреть аналог,проанализировать и понять почему пишут так,а не иначе и как правильно.

Цитата
А ещё я тут подумал...
Светодиоды(сдвиговые регистры) надо цеплять к контроллеру по интерфейсу Universal Serial Interface – USI.
Тогда вся эта программная муть, формирующая клоки и выталкивающая данные в сдвиговые регистры будет заменена кодом конфигурации USI, а потом только регистр подгружай и прерывания лови. Сама передача и тактирование будут выполняться аппаратно.
Правда немного схему переделать придётся, чтобы регистры на нужных пинах оказались, но я думаю это не проблема.

Из сказаного понял немного,но схема то уже спаяна и не хотелось бы делать печатку заново.
sigmaN
Цитата
Цитата
Вы знаете, я ещё не смотрел как там увАжаемый афтар реализовал все эти светодиоды

Насколько я понял 6 групп по 8 светодиодов через регистры CD4094N от МК0 по последовательному порту.
Да я не о том. Я о программировании. То, что они там включены матрицей - сомнений не вызывает.

Цитата
Насколько понял в скобках (1 сдвигаем влево на bit) - в полученом(например 011001 меняем наоборот 100110)проводим отрицание - address будет истина если address и полученное после отрицания тоже истинны?Бр-р-р.Нифига не понял.Нельзя это всё проще выразить?
Хорошо. Допустим
address == 00101001
bit == 3
начинаем считать.
первым делом надо вычислить значение в скобках. Что мы там видим. 1 << bit т.е. берем 1 и сдвигаем её на 3 позиции влево.
Дело мы имеем с байтом. поэтому 1 мы запишем как 00000001 сдвигаем на 3 влево == 00001000
т.е. (1 << bit) == 00001000 запомнили
далее операция ~ применяет НЕ ко всем битам байта. Т.е. ~00001000 == 11110111
далее нужно выполнить операцию &
т.е. address & 11110111
address мы приняли за 00101001
а значит будет выполнено 00101001 & 11110111 и результат будет занесен в address.
выполнив И над каждым битом - получаем результат 00100001
Таким образом мы сняли бит номер 3.

Цитата
Да мне посмотреть примеры кодов,кто как пишет.Как запускают таймер,как отключают,как использовать результат замера времени и т.д.
Тут уж извините, в даташит смотрите как с таймером работать. Запускать его и останваливать. И где результат брать(в каком регистре). Тупое смотрение примеров и copy - paste врятли прибавит мозгов ))

Цитата
Из сказаного понял немного,но схема то уже спаяна и не хотелось бы делать печатку заново.
Ну и ладно. Хотя конечно перекинуть 3 ноги, рзрезав дорожки иприпаяв провода - не так сложно. Может быть потом сделаете таким образом.

Совет: старайтесь больше вникать в суть дела. В теорию. Тупое просматривание примеров не даст результата.
Более того - вы можете научиться плохому. За примером далеко ходить не надо: приведенный в этой теме код автора едва ли можно назвать эталоном для подражания.
В общем пользуйтесь своей головой и не бойтесь вникать в детали. И пусть даже на изучение работы таймера у вас уйдет неделя - вы потом сможете применить его как угодно и где угодно.
А тупо скопировав код из примера - вы становитесь заложником своего непонимания.
RW6MKA
Цитата
Таким образом мы сняли бит номер 3.

Всё это для того что бы снять третий бит в байте???А проще нельзя?

Цитата
Ну и ладно. Хотя конечно перекинуть 3 ноги, рзрезав дорожки иприпаяв провода - не так сложно

Да нет,не сложно это сделать,просто я никакой интерфейс не знаю и поэтому без разницы какой изучать.Можно и USI.

Цитата
Совет: старайтесь больше вникать в суть дела. В теорию. Тупое просматривание примеров не даст результата.

Да вы не правильно поняли,не копирую я тупо куски кода из примеров,но эти куски реально помогают при изучении с нуля.Просто мало кто из "гуру" на форумах снисходит до того,что бы растолковать новичкам простые(отнюдь не для новичков)вещи как вот например на этом сайте:http://atmel.moy.su/publ/1-1-0-4.К сожалению везде обучение новичков сводится к миганию светодиодами и дальше этого дело не идёт,а жаль.
sigmaN
Цитата
Всё это для того что бы снять третий бит в байте???А проще нельзя?
Ну макрос же так и назывался ClrBit(); т.е. очистить бит. Есть там наверно ещё и SetBit(); И это очень просто. Кстати то, что в скобках и операцию ~ компилятор делает "в уме" и генерирует лишь код для операции &. Т.е. для контроллера это тоже очень просто(сам & за 1 такт) ))



Цитата
Да нет,не сложно это сделать,просто я никакой интерфейс не знаю и поэтому без разницы какой изучать.Можно и USI.
Ну это на выбор. Просто так вы будете программно генерировать тактовую частоту и извлекать биты из байта, передавая их на ногу процессора чисто программно(опять же меняя соответствующий бит в байте порта, чтоб нога дёргалась).
А с USI будет всё более цивилизованно - загрузили значение, которое нужно передать и пошел процесс передачи. Всё делает железо, проц свободен. Это более грамотный подход, хотя и не обязательно делать именно так.

Цитата
Просто мало кто из "гуру" на форумах снисходит до того,что бы растолковать новичкам простые(отнюдь не для новичков)вещи как вот например на этом сайте... К сожалению везде обучение новичков сводится к миганию светодиодами и дальше этого дело не идёт,а жаль.
Все, кто чего-то добился - знают, что без самообучения никуда. Также я думаю, что на составление толкового толмуда по тому-же USI для новичков потребуется потратить немало часов. И то найдутся те, которым ничего не понятно. И "гуру" они от того и стали гуру, что берут доку и курят до наступления просветления. Не понимаешь первую же строку - поднимаешь материал по конкретному термину и снова куришь.... вот так становятся гуру.
И вы не поверите, но те, кто для вас гуру - чуть ли не каждый день сталкиваются с чем-то новым и непрерывно самообучаются и решают проблемы.
Да, подсказки, вопросы - всё это будет. Но основную работу придётся проделывать самому. Вы должны быть к этому готовы.

И уж на что что, а на такие вещи как остановка таймера или включение/выключение ноги контроллера, чтобы открылся транзистор - смотреть нечено. Нужно читать даташит, рисовать на бумажечке, если нужно и в голове себе нарисовать чёткую картину что куда и зачем. Вот как только это произошло - считайте что вы на одну ступеньку приблизились к тем, кого сейчас называете гуру.

Вот тут есть учебный курс по AVR. http://easyelectronics.ru/category/avr-uchebnyj-kurs кажется давал уже... или это не в этой теме.. не помню...
И вообще есть и примеры, если и статьи и ответы на форумах тоже... и поиск в гугле тоже то, чем придётся овладеть не хуже, чем языком программирования )
RW6MKA
Цитата
А с USI будет всё более цивилизованно - загрузили значение, которое нужно передать и пошел процесс передачи. Всё делает железо, проц свободен. Это более грамотный подход, хотя и не обязательно делать именно так.

Пока не понимаю о чём речь,но звучит заманчиво.Не подскажите ссылочку а русскоязычный даташит по тиньке2313.У меня в книге Голубцова М.С. очень хорошо описана 90S2313,но она же не аналог тиньки.Нагуглил много но всё по аглицки(только не говорите что нужно учить английский) ))
sigmaN
Нужно!
Нужно знать минимальный набор слов для чтения даташитов. Это не так много. Говорить вас никто не просит, но понимать технический текст надо!

Русский даташит... блин... лично у меня стойкая аллергия на подобные явления.

На поиск в гугле потратил минуты 3....

И даже прикрепляю вам файлик прямо сюда.

Added: тут на коте рекомендовали книжечку http://www.kodges.ru/34902-samouchitel-raz...rojjstv-na.html
сам не читал, но говорят толковая для начинающих.
RW6MKA
Цитата
На поиск в гугле потратил минуты 3....

За это время с моим "быстрым" инетом я хорошо если 5-6 страниц открою crying.gif
Спасибо за ссылки.Сажусь курить доки biggrin.gif до полного просветления.Жаль только с 14 ехать на вахту надо.Инет будет только по телефону,но вопросы,буде таковые возникнут,я и по телефону задам.
314

Вот Вам небольшой примерчик, как делать нежелательно, но возможно. Он под компилятор GCC. В данном устройстве интерфейсы контроллера заняты обменом с другими устройствами, поэтому вывод на цифровые индикаторы+линейка светодиодов сделан так кривенько, через последовательные регистры. Динамическая индикация, две строки по 6 цифр. Регистры 74164. PORTD,4 - вход сброса регистров, он инверсный, PORTB,6 - тактовый, PORTD,5 и PORTD,6 - входа данных регистров символов (цифры), PORTB,7 - вход регистра анодов индикаторов. Из нехорошестей этой функции - слишком большое использование глобальных переменных, неудобно отлаживать и портировать, а так, в общем, работает. Массив индикации 2 на 6 (2 строки на 6 ячеек), count_a - счетчик анодов,

CODE

void indicator (void)

{
register uint8_t i1,j1,A,hlp_ind1,hlp_ind2,hlp_ind3,hlp_ind;
j1=0xff;
if (count_a == 5)

count_a = 0;


else
count_a++ ;


for (i1=0;i1<2;i1++ )
{
A=array_indic[i1][count_a];

switch (A) /* Знакогенератор */
{
case 0:
{
hlp_ind=0xc0;
break;
}
case 1:
{
hlp_ind=0xf9;
break;
}
case 2:
{
hlp_ind=0xa4;
break;
}
case 3:
{
hlp_ind=0xb0;
break;
}
case 4:
{
hlp_ind=0x99;
break;
}
case 5:
{
hlp_ind=0x92;
break;
}
case 6:
{
hlp_ind=0x82;
break;
}
case 7:
{
hlp_ind=0xf8;
break;
}
case 8:
{
hlp_ind=0x80;
break;
}
case 9:
{
hlp_ind=0x90;

}
}
if (A>9) hlp_ind=0xff;
if ((count_a==2)&(i1==0))

{
hlp_ind=array_indic[0][2];

}


if ((alarm==1)&(i1==1))
{
if (counter_delay<20)
hlp_ind=hlp_ind|0x80;
else hlp_ind=hlp_ind&0x7f;
}


if ((count_a==1)&(i1==1)) // засветка точки на индикаторе напряжения

{
hlp_ind=hlp_ind&0x7f;

}
/*if ((count_a==pnt)&(i1==1)) // засветка точки на индикаторе времени

{
hlp_ind=hlp_ind&0x7f;

} */

indic_symbol[i1]=hlp_ind;

}
if (count_a==0) j1=0xf7;
if (count_a==1) j1=0xef;
if (count_a==2) j1=0xdf;
if (count_a==3) j1=0xfe;
if (count_a==4) j1=0xfd;
if (count_a==5) j1=0xfb;



hlp_ind3=j1;

hlp_ind1=indic_symbol[0];
hlp_ind2=indic_symbol[1];

cli();
cbi(PORTD,4); /* сброс регистров индикаторов */
for (i1=0;i1<=2;i1++);
sbi(PORTD,4);
for (i1=1;i1<=2;i1++);
j1=0x80;
for (i1=0;i1<8;i1++) /* последовательная выдача на регистры */
{
cbi(PORTB,6);
if (j1&hlp_ind1)
sbi(PORTD,5);
else cbi(PORTD,5);
if (j1&hlp_ind2)
sbi(PORTD,6);
else cbi(PORTD,6);
if (j1&hlp_ind3)
sbi(PORTB,7);
else cbi(PORTB,7);

sbi(PORTB,6);


j1>>=1;
}



sei();

}
sigmaN
Цитата
Сажусь курить доки biggrin.gif до полного просветления.
А иначе ничего и не будет. Даа. Только так smile.gif
RW6MKA
Не могли бы вы проверить этот кусок исходного кода
Код
word measure(void){
        ClrBit(DDRB,AIN0);                        // Перевести в Z-состояние порты В
        TCNT0 = TH = 0;                                // Очистить счетчик-накопитель
        TCCR0 = PRESC;                                // Включить Таймер 0
        SetBit(DDRB,T);                                // Включить транзистор
        while(BitOff(ACSR,ACO));                // Ждать изменения состояния компаратора
        TCCR0 = 0;                                        // Выключить Таймер 0
        ClrBit(DDRB,T);                                // Выключить транзистор
        SetBit(DDRB,AIN0);                        // Разрядить конденсатор
        delayms(2);                                        // Время для разряда
        return(TH<<8 | TCNT0);                        // Возвращаем результат замера времени
}

Я пробовал посчитать с подстановкой битов у меня получается что возвращаться будет 0???

И ещё вопрос ,почему Code Vision AVR упорно не принимает команду запуска глобальных прерываний __enable_interrupt(); но команду на ассемблере хавает #asm("sei")?
sigmaN
Всё проверять лень(чем-то же и вы должны заниматься ведь так? )
Но могу подсказать, что функция measure возвращает значение типа word - т.е. ДВА байта.
Счётчик у таймера тоже 16ти битный. Т.е. состоит он из двух половинок. TH - хранит старший байт
TCNT0 - младший.
Последняя строка делает следующее:
представим себе некую переменную с типом word. Назовем её по имени фунции - measure
последняя строчка по сути делает присвоение measure = (TH<<8 | TCNT0);
Т.е. берем TH и подвигаем его на один байт в сторону старших разрядов.
Если TH был 11010010 то после операции <<8 получится 1101001000000000 - результат то у нас 16ти битный.
Как-бы таким образом старший байт счётчика таймера встал на своё место (стал старшим байтом ) ).
Дальше сюда надо как-то присовокупить младший байт(TCNT0).
Примем TCNT0 = 00011011
У нас уже есть результат от TH<<8 и он равен 1101001000000000 выполним операцию логического ИЛИ со значением TCNT0 - 00011011
1101001000000000 | 00011011
Для выполнения этой операции TCNT0 будет приведен к типу word путём добавления восьми нулей в старшем байте
т.е. будет так в итоге 1101001000000000 | 0000000000011011
А выполнив эту операцию мы получим 1101001000011011
Что и требовалось.

Цитата
И ещё вопрос ,почему Code Vision AVR упорно не принимает команду запуска глобальных прерываний __enable_interrupt(); но команду на ассемблере хавает #asm("sei")?
Понятия не имею.
Видимо нужно сделать #include или же __enable_interrupt(); - это вообще не из Code Vision AVR... я по WINAVR могу что-то подсказать. CVAVR у меня нет и я им не пользовался ни разу sad.gif
RW6MKA
Цитата
т.е. будет так в итоге 1101001000000000 | 0000000000011011
А выполнив эту операцию мы получим 1101001000011011

Т.е. в данном фрагменте программы,поскольку программа работает не в реальном МК и счётчик таймера ничего не считает,TH и TCNT0 имеют значение 0000000000000000 и в итоге функция = 0,поэтому компилятор выдаёт предупреждение и в принципе на это можно не обращать внимания?

Цитата
Видимо нужно сделать #include или же __enable_interrupt(); - это вообще не из Code Vision AVR...

Но команда __enable_interrupt();это команда включения глобальных прерываний указаная в даташите к tiny2313 или она может меняться в зависимости от компилятора?

И ещё вопрос - правильно ли я понял что,если не было установки портов, то они находяться в третьем состоянии(Z) т.е. в данном случае
Код
ClrBit(DDRB,AIN0);  // Перевести в Z-состояние порты В
DDRB = 0b00?Если это так ,то не вижу смысла в этой строке кода так как порт и так в нужном состоянии.
sigmaN
Цитата
Т.е. в данном фрагменте программы,поскольку программа работает не в реальном МК и счётчик таймера ничего не считает,TH и TCNT0 имеют значение 0000000000000000 и в итоге функция = 0,поэтому компилятор выдаёт предупреждение и в принципе на это можно не обращать внимания?
Что за предупреждение? Я думаю не должен он ни о чем предупреждать ибо TCNT0 и TH должны быть объявлены со словом volatile, что информирует компилятор(обратите внимание: Си компилятор!) о том, что значение переменной может меняться или считываться где-либо за пределами кода, который мы скормили компилятору. Заметьте, что это может быть аппаратное изменение значения(как в случае с таймером) так и программное изменение скажем из обработчика прерывания реализованного на асме )
Без volatile Си компилятор не может понять, что эта переменная нужна в конкретном месте программы и может "закешировать" её значение в одном из регистров и фактического чтения/записи в память не производить.
В нашей функции конечно-же компилятор считает, что наши переменные равны нулю ибо видно их обнуление и не видно откуда у них может появиться что-то отличное от нуля и без volatile компилятор вообще выброст всё, что касается этих переменных, а в конце функции сделает return 0;
Тем не менее Ваш компилятор может компилировать правильно, но всё равно предупреждать и это тоже сгодится за норму... я не могу точно сказать.
Для верности надо бы посмотреть объявление этих самых TH и TCNT0.

Цитата
Но команда __enable_interrupt();это команда включения глобальных прерываний указаная в даташите к tiny2313 или она может меняться в зависимости от компилятора?
Что Вы там в даташите вычитали - я не знаю но суть объясню: в языке Си(в стандарте) вообще не описано ничего относящегося к прерываниям. Равно как и много других особенностей имеющихся на конкретной архитектуре и реализуемой только на асме. Так вот для доступа к таким фишкам придуманы так называемые интринсики. Интринсики эти в каждом компиляторе для каждой платформы свои. Сам по себе интринсик выглядит как функция, но это не функция. На место интринсика во время компиляции вставляется заранее определенная ассемблерная вставка(это всё вшито в компилятор).
Так вот я пологал, что __enable_interrupt(); - это и есть интринсик Вашего компилятора, взамен которого в код фактически вставляется то самое sei
Что там можно было вычитать в даташите про Си код - я не представляю! Даташит относится к девайсу, а не к компилятору.
Однако вы читаете русский даташит, а это означает, что наши умники приложили к нему руку и там может быть что-то типа "все примеры приведены с расчётом на использование компилятора такого-то..." а вы это проморгали и поэтому __enable_interrupt(); у Вас не фурычит ))

Цитата
Код
ClrBit(DDRB,AIN0);  // Перевести в Z-состояние порты В

DDRB = 0b00?Если это так ,то не вижу смысла в этой строке кода так как порт и так в нужном состоянии.
Вам не кажется, что мы по кругу ходим? Ведь разбирали же не так давно макрос ClrBit(); Вы уже должны понимать, что этот код чистит бит AIN0 регистра DDRB. Это не тоже самое, что всему регистру присвоить 0! 0 присваивается одному единственному биту!
Кстати тут по сути вывод AIN0 конфигурируется как входной. Никакого Z-состояния нет. В случае если встроенный pull-up резистор отключен - порт не будет создавать особого тока, но всё-же это не высокоимпедансное состояние(вывод порта физически соединен со схемой внутри контроллера). Так что это опять похоже заморочки вашего АФФТАРА smile.gif)
314
В tiny2313 таймер0 8-битный, ТН скорее всего должна инкрементироваться где-то в обработчике прерывания по переполнению таймера0.
RW6MKA
sigmaN
Цитата
Что за предупреждение? Я думаю не должен он ни о чем предупреждать ибо TCNT0 и TH должны быть объявлены со словом volatile,

Да, TH обьявлен как volatile byte.Компилятор по этой строке выдаёт два предупреждения:
Warning: dira.c(173): shift result will be 0(перемещаемый результат = 0)
Warning: dira.c(173): overflow is possible in 8 bit shift left, casting shifted operand to 'int' may be required(переполнение возможно в 8 битах перемещённых влево,для подсчёта преремещений может потребоваться операнд int.
Тут у меня попутно созрел ещё вопрос
Цитата
Счётчик у таймера тоже 16ти битный. Т.е. состоит он из двух половинок. TH - хранит старший байт
TCNT0 - младший.
но таймер0 вроде 8-битный,откуда старший байт?

Цитата
"все примеры приведены с расчётом на использование компилятора такого-то..." а вы это проморгали и поэтому __enable_interrupt(); у Вас не фурычит ))

В точку!

Цитата
Вам не кажется, что мы по кругу ходим? Ведь разбирали же не так давно макрос ClrBit(); Вы уже должны понимать, что этот код чистит бит AIN0 регистра DDRB. Это не тоже самое, что всему регистру присвоить 0! 0 присваивается одному единственному биту!
Кстати тут по сути вывод AIN0 конфигурируется как входной. Никакого Z-состояния нет.

Не совсем понимаю зачем чистить бит AIN0 если он установлен 0
Код
#define AIN0  0
и биты этой ноги DDB0=0;PORTB0=0 а это третье состояние(так по крайней мере в даташите указано)

314
Цитата
ТН скорее всего должна инкрементироваться где-то в обработчике прерывания по переполнению таймера0.

Это как?Чуть подробнее можно,для чайника.

Да,компилятор ругается ещё на одну строку
Код
__eeprom word dummy[8]= {0,0,0,0,0,0,0,0};
и предупреждает:Warning: dira.c(64): global variable 'dummy' was declared, but not referenced(глобальная переменная 'dummy' была обьявленна,но на неё нет ссылок.
sigmaN
Цитата
Warning: dira.c(173): shift result will be 0(перемещаемый результат = 0)
Warning: dira.c(173): overflow is possible in 8 bit shift left, casting shifted operand to 'int' may be required
Это весьма странно, т.к. есть такая штука как integer promotion.
Ааа, вот нашел http://electronix.ru/forum/index.php?showtopic=46523 Это фишка вашего компилятора.

Цитата
но таймер0 вроде 8-битный, откуда старший байт?
в обработчике прерывания таймера должен быть инкремент TH каждый раз, когда TCNT0 "перескакивает через 255" в 0.
Таким образом получается программная 16ти битность )

Цитата
Не совсем понимаю зачем чистить бит AIN0 если он установлен 0
Код
#define AIN0 0
и биты этой ноги DDB0=0;PORTB0=0 а это третье состояние(так по крайней мере в даташите указано)
Уважаемые знатоки, а разве применительно к пину, сконфигурированному как input с отключенной подтяжкой можно применить термин Tri-state (Hi-Z) ??
Википедия говорит:
Цитата
Высокоимпедансное состояние или Z-состояние — такое состояние контакта логической схемы, при котором сопротивление между этим контактом и остальной схемой очень велико

А зачем там аффтар чистит этот бит? Но ведь перед выходом из функции он его ставит
Код
SetBit(DDRB,AIN0);                        // Разрядить конденсатор
значит до следующего вызова функции этот бит таки стоит и аффтар чистит его перед измерением..

Цитата
Warning: dira.c(64): global variable 'dummy' was declared, but not referenced
Ну у вас пока нет кода, который бы обращался к dummy. Объявление есть, но переменная не используется.
RW6MKA
За ссылку спасибо,разобрался всё работает.
Цитата
в обработчике прерывания таймера должен быть инкремент TH каждый раз, когда TCNT0 "перескакивает через 255" в 0.
Таким образом получается программная 16ти битность )

Блин,а в даташите практически об этом ни слова.

Цитата
Уважаемые знатоки, а разве применительно к пину, сконфигурированному как input с отключенной подтяжкой можно применить термин Tri-state (Hi-Z) ??

???Но ведь именно так написано в даташите:-"Третье или состояние Z,когда ({DDB0,PORTB0}=0b00),выводы являются входами и имеют высокое входное сопротивление". Я чёт совсем запутался.Как правильно то будет?

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

Да,тут я проморгал. blush.gif Дествительно автор устанавливал этот бит.

Цитата
Ну у вас пока нет кода, который бы обращался к dummy. Объявление есть, но переменная не используется.

Т.е.можно не обращать внимания на это предупреждение?
sigmaN
Цитата
Блин,а в даташите практически об этом ни слова.
Да там и об использовании компаратора для измерения напряжения - тоже ни слова cranky.gif Это Ваша программа. Вы там можете хоть 128ми битный счётчик сделать.... об этом не должны писать в даташите. Даташит - это описание чипа. Там вообще подобную информацию искать бессмысленно. Даже удивительно, что вы такое написали....

Цитата
Но ведь именно так написано в даташите:-"Третье или состояние Z,когда ({DDB0,PORTB0}=0b00),выводы являются входами и имеют высокое входное сопротивление". Я чёт совсем запутался.Как правильно то будет?
Ну видел я там это, да. И понятно, что входное сопротивление такого пина получается весьма большим, но всё-же я высказал сомнение насчёт корректности термина в этом случае. Ведь
Цитата
Высокоимпедансное состояние или Z-состояние — такое состояние контакта логической схемы, при котором сопротивление между этим контактом и остальной схемой очень велико
но между самой ногой контроллера и его схемой сопротивление то не большое! Большое сопротивление получается в таком случае относительно общего провода(GND) контроллера. Вот о чем я.

Цитата
Т.е.можно не обращать внимания на это предупреждение?
конечно, забейте на это и всё.
sigmaN
Что-то чем дальше, тем меньше мне нравится Ваш этот CVAVR...слезайте с него, это не Си.Выбрось каку!!!

И интегер промоушнз там не единственный прикол sad.gif
Заучите все эти примочки, а потом будете локти кусать...
Переползайте ка вы на GNU.
С сайта Atmel стяните студию и toolchain и начинайте с нормальным компилятором работать...мой Вам добрый совет )

http://www.atmel.com/dyn/products/tools_ca...sp?tool_id=2725 - страничка студии
качать(ставить в порядке перечисления):
AVR Studio 4.18 (build 684) (116 MB, updated 11/09)
AVR Studio 4.18 SP3 (b716) (31 MB, updated 9/10)
AVR Toolchain Installer (87 MB, updated 9/10) For use with AVR Studio 4.18 SP3

Вот. И давайте на теорию налягайте. Чувствуется, что даже в битовых операциях плаваете....
RW6MKA
Цитата
Что-то чем дальше, тем меньше мне нравится Ваш этот CVAVR...

Да,мне то же.Но зато по нему есть хорошая книга на русском,а остальные компиляторы этим похвастаться не могут.
Студия4 у меня есть,но без SP3 и toolchain,а вот как и что там делать почитать негде.
А с прогой от аффтара явно что то не то.Я прошил МК прошивкой которую он прислал вместе с исходником(соответственно выставив фьюзы чтобы tiny2313 иммитировала 90S2313),результат плачевный - вообще ничего не работает.Я грешил на неполную совместимость МК.В CVAVR преределал исходник под тиньку(осталось только предупреждение по __eeprom word dummy[8]= {0,0,0,0,0,0,0,0}wink.gif компилится без проблем, прошил этой прошивкой результат такой же.Аффтар пишет что устройство с этой прошивкой работало нормально,но прокомментировать фрагменты кода отказался,сылаясь на занятость.Вообщем что бы убедится в работоспособности данного кода нуна гдето родной МК раздобыть.
Жаль что завтра на работу ехать,но литературку беру с собой,буду налегать на теорию biggrin.gif
sigmaN
Да отвяжитесь вы от этой прошивки и её автора!
НЕчему там учиться и компилить тупо тоже там нЕчего. Своё надо делать и по правильному!
RW6MKA
Обидно,да.Я так понимаю,если человек выкладывает в инет на всеобщее обозрение свою конструкцию,то должен быть готов в любой момент дать исчерпывающие обьяснения по работе устройства и его програмному обеспечению.А он не смог даже сказать как включаются кнопки.Из схемы можно предположить что происходит замыкание контактов S0,S1,S2 с RET,но это ж предположение.
Студию скачал,установил,но ещё не юзал.Приеду буду осваивать,а пока не порекомендуете литературку по ней на русском?
sigmaN
Не порекомендую. не о чем там читать. Создаёте проект. в свойствах ставите нужный камень - далее как обычно в проект добавляете файлы и жмете кнопочку Build. Если немного включить интуицию и чутьё - вы получите информацию прямо из первоисточника(от интерфейса среды). Не стесняйтесь включать моск и разбираться, что называется, на ходу. Без этого вы так и останетесь на уровне поиска готовых решений и русских мануалов.

Автор уже в годах, на сколько я понимаю... кто знает, может и забыл уже что там и как у него было.... smile.gif
RW6MKA
Вот рекомендуют перед установкой студии ставить WinAVR для программирования в студии на С,это так или это действительно для старых версий?
sigmaN
тулчайн - это и есть тот самый WinAVR.
Только лично у меня были проблемы с путями при использовании WinAVR я их вводил вручную.
С тулчайном таких проблем не было. Всё сразу работало без проблем.
Я же Вам сказал что каать и ставить в том порядке, в котором я перечислял. Всё проверено ))
sigmaN
Абсолютно случайно наткнулся на статью http://easyelectronics.ru/kondensator-i-rc-cepochka.html где почти в самом конце есть описание процесса измерения напряжения с помощью компаратора. Да и вся статья, думаю, будет очень полезна.
314
По мне, так проще все делать сразу в Programer_Notepad, без студии. Студия полезна как дебаггер, для пошаговой отладки (интерфейс удобный) и еще удобный программатор, а писать и компилить все-таки PN удобнее, ИМХО.
А по-поводу автора, так может ему программу внук писал smile.gif .
sigmaN
ИМХО пусть привыкает к работе над проектом в IDE. Концепция везде одинакова. Пригодится.
Сам я тоже студию не очень люблю за тупость редактора и предпочитаю SlickEdit, но если сейчас предложить такой вариант топикстартеру - придётся ещё и русский мануал по SlickEdit или Programer_Notepad искать )
А программки простенькие у него....так что должно студии пока хватать.
RW6MKA
Всё установил как рекомендовали и спасибо за ссылочку.Литературки по студии немного накропал по инету(ну в смысле первые шаги и пр.)буду изучать.Жаль что через 5 часов уезжать на вахту.
Да,об исходнике.Попробовал я его прокомпилить в IAR Systems Embedded Workbench 5.4 результат 70 ошибок и 0 предупреждений crying.gif вот так.Буду писать прогу под эту схему с нуля.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.