Два идиотских вопроса про Keil&SiLabs (+)
(«Телесистемы»: Конференция «Микроконтроллеры и их применение»)

миниатюрный аудио-видеорекордер mAVR

Отправлено O.L. 02 августа 2004 г. 11:22

Вопрос первый,- про странные Bаudrate в симуляторе от Keyl-а и дебагере от SiLads-а:
Пишем простенькую программку: // :)


#include // SFR declarations
#include "stdio.h"
#define SYSCLK 24500000L // SYSCLK frequency in Hz
#define BAUDRATE 19200L

// - function init ---------------------------------------
sendBit_of_Byte (uchar);// выводит uchar в виде 0bxxxxxxxx
// реализацию опускаю дабы не загромождать. тем более, что на суть вопроса это не влияет
send_CR (); // просто перевод строки

Init_Device(); // весь инит наверное то же не стоит приводить, большой однако :)
// приведу только UART0_Init потому как именно с симуляцией UART0 проблемы.
// - serial port init ------------------------------------
// Configure the UART0 using Timer1, for and 8-N-1.
//
void UART0_Init (void)
{
SCON0 = 0x10; // SCON0: 8-bit variable bit rate
// level of STOP bit is ignored
// RX enabled
// ninth bits are zeros
// clear RI0 and TI0 bits
if (SYSCLK/BAUDRATE/2/256 < 1) {
TH1 = -(SYSCLK/BAUDRATE/2);
CKCON &= ~0x0B; // T1M = 1; SCA1:0 = xx
CKCON |= 0x08;
} else if (SYSCLK/BAUDRATE/2/256 < 4) {
TH1 = -(SYSCLK/BAUDRATE/2/4);
CKCON &= ~0x0B; // T1M = 0; SCA1:0 = 01
CKCON |= 0x01;
} else if (SYSCLK/BAUDRATE/2/256 < 12) {
TH1 = -(SYSCLK/BAUDRATE/2/12);
CKCON &= ~0x0B; // T1M = 0; SCA1:0 = 00
} else {
TH1 = -(SYSCLK/BAUDRATE/2/48);
CKCON &= ~0x0B; // T1M = 0; SCA1:0 = 10
CKCON |= 0x02;
}

TL1 = TH1; // set Timer1 to overflow immediately
// TMOD: timer 1 in 8-bit autoreload
TMOD &= ~0xf0; // mode
TMOD |= 0x20;
TR1 = 1; // START Timer1
TI0 = 1; // Indicate TX0 ready
}
// - test function pointer -------------------------------
typedef void( *FUNCTION )( void );
void Func_A (void)
{
puts ("Port0 ");
sendBit_of_Byte (P0); send_CR ();
puts ("Port1 ");
sendBit_of_Byte (P1); send_CR ();
puts ("Port2 ");
sendBit_of_Byte (P2); send_CR ();
}
void Func_B (void)
{
puts ("Timer1 con.reg. TCON == ");
sendBit_of_Byte (TCON); send_CR ();
printF_char ("Timer1 high.reg. TH1 == ");
sendBit_of_Byte (TH1); send_CR ();
}
void Func_C (void)
{
printF_char ("uart0 con.reg. TCON == ");
sendBit_of_Byte (SCON0); send_CR ();
}
static FUNCTION func[3] = { Func_A, Func_B, Func_C };

unsigned char i;
// - main programm area ----------------------------------
void main (void)
{
Init_Device();
putchar (0x09);
i=0;
do {
func[i]();
}while(++i<3)
}
//----------------------------------------------------------------------------


Вот...
А теперь по существу. Приведенное выше нормально работает и выводит состояние регистров
в терминалку компа на скорости 19200 в моде 8-N-1.
Но, при этом, симулятор от Keil-а в окошке Serial Channell 0 сообщает, что :
- Mode 8bit, var Baudrate // это и нужно
- SCON0 == 0x12 // здесь не учтен 7-ой бит, который всегда читается как '1'
// в итоге должно быть 0х52 или 0x50
- Baudrate
transmit&receive == 2 041 666 // ?

В дебагере SILICON LABORATORIES C8051Fxxx uVISION2 DRIVER в окошке Serial Channell 0
- Mode 9bit var.Baudrate // ?
- SCON0 == 0x52 (0x50)
- Baudrate
transmit&receive == 4889 // ?

На терминал выводится
uart0 con.reg. TCON == b01010000 // как бы все правильно.

Используемый Timer 1 симулируется правильно и соответствует тому, что выводится на терминал
Timer1 con.reg. TCON == b11000000 // 0xC0
Timer1 high.reg. TH1 == b01100001 // 0x61

За то время, пока я работаю с контроллерами Cygnal (SiLabs) несколько раз обновлялся и Keil и драйверы от Cygnal, но эти "приколы" с сериальноком кочуют из одной версии в другую. Я уже и не знаю, что предполагать. Либо создатели этих программных продуктов вообще не тестируют то что пишут, по причине отсутствия специалистов, либо это мои персональные глюки :)...

И втой вопрос.
Вышеприведенный пример программы перестает работать, если переменную i сделать локальной объявв внутри функции main, то есть, вот так:


// - main programm area ----------------------------------
void main (void)
{
unsigned char i;
Init_Device();
putchar (0x09);
i=0;
do {
func[i]();
}while(++i<3)
}

В этом случае получается мертвый цыкл. Переменная i никогда не будет равна 3. Я пробовал вызывать функции A,B и C последовательно без цикла, вот таким образом:

i=0;
func[i](); ++i;
func[i](); ++i;
func[i]();

Результат тот же, последнего инкримента не происходит (это хорошо видно в ассемблерном листинге), i всегда "замерзает" на значении 1. Все нормально работает, если i опять объявить как глобальную.
Уровень оптимизации на это ни как не влияет (кроме как на размер IntelHEX). Надо сказать, крови это мне попортило изрядно.
Упоминания о таком поведении компайлера, когда он так по-разному обрабатывает локальные и глобальные переменные, я не видел.
Так вот, с точки зрения стандарта С, я допустил ошибку, когда пытался использовать локальную переменную в качестве индекса указателя на функции, или это очередная "шутка" дядюшки Keil-a?

Составить ответ  |||  Конференция  |||  Архив

Ответы



Перейти к списку ответов  |||  Конференция  |||  Архив  |||  Главная страница  |||  Содержание  |||  Без кадра

E-mail: info@telesys.ru