Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Программирование МК на Си
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Mackeda
Здравствуйте.

Возникло пару вопросов начального уровня по программированию МК на Си.

1) Подскажите как расчитать время задержки, если частота на микроконтроллере 9 МГц. Пример кода ниже.
Я считаю так: для первого Delay, каждые 111 нс (9МГц) от числа 82 (загруженного из Delay1) будет отниматься 1, когда дойдет до нуля цикл завершится. Получим задержку 111 нс * 82 = 9.102 мкс.


2) Почему переменная j инициализируется числом 1000.

Код
void Delay1(unsigned int j)    
    {
    while(j--)
        Delay(82);
    }            

void Delay(unsigned int i)  
    {    
    while(i--);
    }


3) В uVision есть окно прерываний (рисунок).

EA - общий запрет/разрешение прерываний.
EX0 - разрешение внешнего прерывания INT0.
Не до конца понял назначение IT0 и не понял IE0.

4) Поясните код
Код
void INTRPT0(void) interrupt 0 using 1
, ето что специальная функция на СИ, которая срабатывает когда на ноге INT0 появляется "0".

5) Что возвратит строка
Код
return !INT0;
, если sbit INT0 = 0xB2 и на порту INT0 лог. "0". Будет возвращена "1".

6)

#define ADDR 0x02
#define ERROR PBYTE[ADDR]

Если я напишу ERROR (0xFF), во внешнюю память запишется данные 0xFF? Просто данные без адреса?

Заранее благодарю за ответы.
Палыч
Хорошо бы задавая вопрос указывать конкретный тип МК, для которого Вы пишите программу... Я, так понял, что какой-то клон 51 серии...

1. Каждый оператор языка Си вовсе не обязательно выполняется за один такт процессора. Оператор языка Си, обычно (не всегда, конечно), переводится транслятором в несколько команд. Каждая команда в МК51 выполняется за несколько (от 1 до 3) циклов процессора; каждый цикл - несколько (в "классике" - 12) тактов генератора... В общем случае нужно по ассемблерному коду посчитать время выполнения функции Delay от её аргумента - зависимость будет, примерно, такой: Т= X * i + Y в циклах процессора...

PS. Если в настройках проекта правильно указать тип МК и тактовую частоту, то в отладчике можно посмотреть время выполнения участка программы.

2. Не понятно: о чём идёт речь?

3. Это - соответствующие биты регистра TCON

4. В МК есть такое понятие - "прерывание". При определенных условиях происходит прерывание "естественной" последовательности команд, и переход на процедуру обработки прерывания. Стандарт языка Си не предусматривает прерываний. Приведенная Вами конструкция - заголовок процедуры прерывания.

5. В общем случае - возвратит "не ноль".

6. Если Вы запишите ERROR= 0xFF; то во внешнюю память по адресу 2 (поскольку ADDR то же самое, что 0х02 = 2) будет записано FF
Mackeda
Цитата
2. Не понятно: о чём идёт речь?


Изначально переменная j инициализируется нулем, но после первого инкремента while(j--) в ней появляется число 03Е7h = 999b. Почему так ?


Цитата
4. В МК есть такое понятие - "прерывание". При определенных условиях происходит прерывание "естественной" последовательности команд, и переход на процедуру обработки прерывания. Стандарт языка Си не предусматривает прерываний. Приведенная Вами конструкция - заголовок процедуры прерывания.


То есть процедура будет выполнена когда на INT0 появится "0".

Цитата
5. В общем случае - возвратит "не ноль".


Можно подробней?


Еще вопрос:

Есть цепочка вызовов функций на Си, не понятен результат в IS_ER.
Код
#define IS_ER (!(GetERROR()&0x10))



while(1)
{
....................................          

if(!IS_ER)
                              return;
}



       GetERROR(void)    
     {
    return (ERROR|0x8F);
      }



Понимаю так, когда программа доходит до if(!IS_ER), она проверяет что в переменной IS_ER, там функция GetERROR, смотрит ее, там еще одна функция ERROR(определение функции ERROR в первом посте). С внешней памяти с ячейки под адресом 0x02 считывает данные (8 разрядный код), далее над ними выполнится по битная операция ИЛИ и числом 0x8F. Результат будет так же иметь 8 бит. Далее, результат подставится в место вызова, а это GetERROR(), тут над результатом функции и числом 0х10 выполняется логическое И результат инвертируется и передается в IS_ER. Если так размышлять то в IS_ER попадет 8 битное число, чего быть не может, ведь там IF. Где я ошибаюсь?
toweroff
Цитата(Mackeda @ Jan 3 2012, 15:32) *
но после первого инкремента while(j--)

нет, после декремента

Цитата(Mackeda @ Jan 3 2012, 15:32) *
Еще вопрос:

Есть цепочка вызовов функций на Си, не понятен результат в IS_ER.
Код
#define IS_ER (!(GetERROR()&0x10))
while(1)
{
....................................          

if(!IS_ER)
                              return;
}

Понимаю так, когда программа доходит до if(!IS_ER), она проверяет что в переменной IS_ER

это не переменная.
Препроцессор сгенерит вот такой код, который скормится компилятору
Код
#define IS_ER (!(GetERROR()&0x10))
while(1)
{
....................................          

if(!(!(GetERROR()&0x10)))
                              return;
}

после выполнения всех битовых операций результат будет подставлен в if
в результате получим:
GetERROR()&0x10 - выделяем 4-й бит
побитовая инверсия результата
еще одна инверсия

далее if проверяет результат - если он будет НЕ НОЛЬ, то выполнится тело if
Mackeda
Цитата
нет, после декремента


Сори за опечатку, да после дикремента, том почему так?

Цитата
далее if проверяет результат - если он будет НЕ НОЛЬ, то выполнится тело if


Если результат постоянно будет "1", программа не выйдет из цикла while(1)?
toweroff
Цитата(Mackeda @ Jan 3 2012, 16:32) *
Сори за опечатку, да после дикремента, том почему так?

смотрите
допустим, имеем беззнаковую переменную размером 8 бит
инициализируем нулем (00000000b)
теперь пробуем вычесть из нее 1
получаем 11111111b или 0xFF
почему у Вас получается другое значение? возможно, в теле цикла переменная еще как-то модифицируется

Цитата(Mackeda @ Jan 3 2012, 16:32) *
Если результат постоянно будет "1", программа не выйдет из цикла while(1)?

да
Палыч
Цитата(Mackeda @ Jan 3 2012, 15:32) *
Изначально переменная j инициализируется нулем, но после первого инкремента while(j--) в ней появляется число 03Е7h = 999b. Почему так ?
Что значит "переменная j инициализируется нулем" ? В данном случае: j - параметр функции Delay1; вероятно, в программе есть вызов функции Delay1(1000); при этом переменная j (та самая, которая - параметр функции Delay1, возможно, есть ещё одна переменная j, которая "инициализируется нулём" - это совсем другая переменная) примет значение 1000, а после дикремента - значение 999.

Цитата(Mackeda @ Jan 3 2012, 15:32) *
То есть процедура будет выполнена когда на INT0 появится "0".
Если быть формалистом, то процедура будет выполнена, если установлен флаг IE0 в регистре TCON, при этом установлены EX0 и EA в регистре IE. Для "классики" этого достаточно (в других МК могут быть ещё условия). Неважно - каким образом оказался установленным бит IE0 (выполнилось условие, установленное битом IT0 регистра TCON, или, например, некоторой командой).

Цитата(Mackeda @ Jan 3 2012, 15:32) *
Можно подробней?
Результат логической операции - ноль (ложь), или "не ноль" (любое значение, отличное от нуля).
Mackeda
Подскажите еще момент.

Код
while(1)
       {
    
        if(!ERROR1)
            {
            ...........                
            return 1;
            }
        else
            if(ERROR1)
            ..............    
                        return 0;


Программа выйдет из цикла while когда !ERROR1 будет равен "0", а при "1" зависнет в цикле?
MALLOY2
А как надо ? какая-то ахинея. Пишите что бы было всегда всем понятно.
Код
while(1)
{
   if(ERROR1 == 0)
   {
      ...........                
      return 1;
   }
   else
   {
     ........
     return 0;
  }
}

Только не совсем понят5ен смысл этого кода, который при первой же итерации выйдет.
Mackeda
Уточняю.

Код
Выполнение программы:

Шаг 1  ........
Шаг 2  while(Init()==0); // ожидание инициализации (пока не  возвратит 0)
Шаг 3 ........................

переходит к функции Init

bit Init(void)  
    {
    while(1)
        {
                
        if(!ERROR1) // проверяет что возвращает функция ERROR1 (она большая  поэтому ее не привожу)
            {
             ...........  
                         return 1;
            }
        else
                if(ERROR2) // проверяет что возвращает функция ERROR2 (тут допустил ошибку в предыдущем коде нужно проверять ERROR2 )
                
                        return 0;
        }
    }


Правильно ли я понял: программа перейдет на Шаг 3, только в случает если ERROR1 = 1, ERROR2 = 1.
Палыч
Цитата(Mackeda @ Jan 10 2012, 15:18) *
Правильно ли я понял: программа перейдет на Шаг 3, только в случает если ERROR1 = 1, ERROR2 = 1.

Точнее будет сказать: если ERROR1 и ERROR2 примут значение, отличное от нуля (единицы тоже подойдут biggrin.gif ).
XVR
Цитата(Mackeda @ Jan 10 2012, 15:18) *
Правильно ли я понял: программа перейдет на Шаг 3, только в случает если ERROR1 = 1, ERROR2 = 1.
Если учесть, что ваш 'Шаг 2'
Цитата
Шаг 2 while(Init()==0); // ожидание инициализации (пока не возвратит 0)
закончится когда Init() вернет не 0 (в коментарии у вас написанно ровно наоборот), то 'Шаг 3' наступит когда ERROR1 вернет 0
редактор
Проверять значение вызываемой функции надо так
Код
if (ERROR!())
   { return 1;
     }


иначе проверяется указатель или адрес функции (в примере отсутствуют скобки после имени функции)
Палыч
Цитата(редактор @ Jan 13 2012, 12:32) *
Проверять значение вызываемой функции надо так
if (ERROR!())

О как у Вас отрицание куда-то "уехало"!
_Pasha
Цитата(Mackeda @ Jan 10 2012, 15:18) *
Уточняю.

Шаг 1 ........
Шаг 2 while(Init()==0); // ожидание инициализации (пока не возвратит 0)
Шаг 3 ........................


Правильно ли я понял: программа перейдет на Шаг 3, только в случает если ERROR1 = 1, ERROR2 = 1.

Обычно оборачивают так
Код
bit Init(void)  
{
  do{
    if(ERROR1){/*обработка именно ошибочной ситуации*/; break;}
    if(ERROR2){/*обработка ошибочной ситуации 2*/; break;}
    return 1;//успешная инициализация
  }while(0);
  return 0;
}
Mackeda
Цитата
Если быть формалистом, то процедура (прерывания) будет выполнена, если установлен флаг IE0 в регистре TCON, при этом установлены EX0 и EA в регистре IE. Для "классики" этого достаточно (в других МК могут быть ещё условия). Неважно - каким образом оказался установленным бит IE0 (выполнилось условие, установленное битом IT0 регистра TCON, или, например, некоторой командой).


А можно программно установить на ноге INT 0 уровень логического нуля? Или эта нога только как вход работает.
Палыч
Цитата(Mackeda @ Jan 18 2012, 17:20) *
А можно программно установить на ноге INT 0 уровень логического нуля?

Можно
Vladimir_Sn
Здравствуйте!
Сейчас пишу первый проект на микроСи, до этого работал только на асме для микрочипа. Не могу разобраться что происходит. Подскажите пожалуйста.
Код
  dif_res = (delta_1 - delta_0) * Kd;
// delta 0 = 760
// delta 1 = 0
// dif_res становится равным 65384, почему, и откуда берётся это число?
//  signed int delta_0, delta_1, dif_res;
//   const float Kd = 0.2;

Палыч
Цитата(Vladimir_Sn @ Jan 21 2012, 10:02) *
Не могу разобраться что происходит.

Вспомните (узнайте, если не знали) про дополнительный код. Значение переменной dif_res равно минус 152. Число 65384 имеет такое же представление в памяти, что и минус 152,, но для беззнаковых целых (unsigned int).
Cosmojam
А ещё умножение float на int и присваивание результата в int. Вспомните 1/3 и 1.0/3/0
Но лучше дроби не использовать там где это возможно. Умножение на 0.2 заменяется цельночисленным делением на 5 если точность устраивает. Если нет, то см выше.
Vladimir_Sn
Теперь начинаю понимать..., спасибо большое!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.