Нескольно простых вопросов о программировании AVR на Си.
Передатчик и приемник - два разных микроконтроллера, никак не синхронизированные. Включаем питание, по программе включется UART и там и там. Но момент то включения разный. Понятно, что определенный, но не для контроллеров относительно друг друга.
We do what we must because we can (c) GLaDOS
- Реклама
Если передатчик постоянно, без всяких пауз, долбит байт за байтом - руки оторвать такому разработчику.
Между пакетами в передатчике всегда делается пауза, для синхронизации с ним приёмной стороны.
Если пауз никаких нет, то вы никак не ссинхронизируетесь ни со старт-битом, ни, тем более, с началом пакета.
Между пакетами в передатчике всегда делается пауза, для синхронизации с ним приёмной стороны.
Если пауз никаких нет, то вы никак не ссинхронизируетесь ни со старт-битом, ни, тем более, с началом пакета.
Ну это алгоритм работы Одесского базара. В реальных сетях есть, как правило, мастер и слейв. Работают они по логическому протоколу. Мастер дает запрос, слейв (-ы ) отвечает.baron_P писал(а):начнется передача на передатчике и прием на приемнике (жуть какая)
Если надо врубиться в чужую сеть ( шпионские страсти ), то надо дождаться тайм-аута ( состояние стоп-біта в течение времени > времені передачі одного байта [ блін, на украінскую раскладку перескочіло - хакеры ? - у меня на компе ее нет!] ) . І с этого момента ждать стартового біта. Прі этом нужно знать параметры передачі ( см. выше ) . Теоретіческі можно, думаю, программно іх определіть і к нім подстроіться, практіческі мне не пріходілось, да і нах.
Но это уже далеко за рамкамі спрошенного вопроса.
Спасибо, в том и был вопрос. Синхронизация идет через паузу передатчика. В обучалках этот момент мне не попадался в явном виде, а сам долго доходил до самой необходимости такой синхронизации при асинхронной передаче. Теперь стало ясно, чего оно у меня не шевелится.Аlex писал(а):Если передатчик постоянно, без всяких пауз, долбит байт за байтом - руки оторвать такому разработчику.
Между пакетами в передатчике всегда делается пауза, для синхронизации с ним приёмной стороны.
Если пауз никаких нет, то вы никак не ссинхронизируетесь ни со старт-битом, ни, тем более, с началом пакета.
We do what we must because we can (c) GLaDOS
Ой, что-то Вы темните - разве "ы" есть в украинской раскладке? Да и "и" в ней вроде как на том же месте, что и в русской.Jack_A писал(а): блін, на украінскую раскладку перескочіло - хакеры ? - у меня на компе ее нет!
- Реклама
Пис'ал с обчественного компа и вдруг ни с того ни с сего EN=B RU=i . Раскладка, конечно, нашенская, белорусская. Но откуда ей взяться ? Впрочем, комп ничейный, лапают кому не лень. Могло быть и хуже.
объясните мне тупому пожалуйста, как работать с глобальными переменными. Почему компилится с ошибками?
- Вложения
-
- test_c.rar
- проектик на 5 строчек
- (3.78 КБ) 203 скачивания
Во первых не подключена ни одна библиотека, а во вторых не подключена библиотека sub1.c
надо прописать #include "sub1.c"
надо прописать #include "sub1.c"
господи, ну сколько можно?!rxstart1 писал(а):Во первых не подключена ни одна библиотека, а во вторых не подключена библиотека sub1.c
надо прописать #include "sub1.c"
никогда не подключайте сишные файлы директивой #include !!!!
ну хотя бы самый простенький букварик по Си прочтите, наконец!
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Ну это понятно, а по существу?ARV писал(а):господи, ну сколько можно?!rxstart1 писал(а):Во первых не подключена ни одна библиотека, а во вторых не подключена библиотека sub1.c
надо прописать #include "sub1.c"![]()
![]()
![]()
никогда не подключайте сишные файлы директивой #include !!!!
ну хотя бы самый простенький букварик по Си прочтите, наконец!
Ну все разобрался, всем спасибо...
- Сообщения: 15
- Зарегистрирован: Пн май 05, 2014 11:59:11
Всем, Привет! Никто не работал с OLED дисплеем на контроллере SSD1306? как закрасить любой пиксель на экране?
Информации просто море по нему, в чём конкретно проблема ?
- Сообщения: 15
- Зарегистрирован: Пн май 05, 2014 11:59:11
Да хочу функцию написать по закрашиванию пикселя по координатам
что то вроде:
x = 50;
y = 60;
draw_pixel(x, y);
собственно мне нужны команды для выхода на эти координаты, пока есть только идея использовать 21h и 22h, но там сообщение длинное получается
Еще я по команде 81h не могу изменить контраст(((
У меня пока получился такой вариант:
что то вроде:
x = 50;
y = 60;
draw_pixel(x, y);
собственно мне нужны команды для выхода на эти координаты, пока есть только идея использовать 21h и 22h, но там сообщение длинное получается
Еще я по команде 81h не могу изменить контраст(((
У меня пока получился такой вариант:
Код: Выделить всё
void draw_pixel_lcd(uint8_t _adress, uint8_t _x, uint8_t _y){
uint8_t __x = 0;
while(_x > 7){
_x -= 8;
__x ++;
}
send_command_lcd(_adress, 0x21); //Set Column Address (21h)
send_command_lcd(_adress, _y);
send_command_lcd(_adress, _y);
send_command_lcd(_adress, 0x22); //Set Page Address (22h)
send_command_lcd(_adress, __x);
send_command_lcd(_adress, __x);
send_data_lcd(_adress, 1<<_x); //Draw pixel
}
- Сообщения: 574
- Зарегистрирован: Вт ноя 02, 2010 17:46:37
Добрый день, подскажите как более правильно организовать следующую библиотеку.
service_timer.с
service_timer.h
Используется она достаточно просто servic_timer запускаем в таймер и всё дальше только работаем с Enum и не забываем изменять MAX_TIMERS
Так вот проблема в том что в одном проекте может быть 5 счётчиков в другом 10 в третьем 25
по этому файл service_timer.h от проекта к проекту меняется и приходится копировать его, что я думаю не совсем правильно.
А создавать ещё один файл который содержит только enum тоже как-то не то.
Как в таком случае создать библиотеку? (единую для всех проектов)
и где и как лучше разместить различия?
service_timer.с
Спойлер
Код: Выделить всё
#include <service_timer.h>
volatile unsigned int Timir[MAX_TIMERS];
unsigned int GetTimers(unsigned char timers){
return Timir[timers];
}
void ResetTimers(unsigned char timers){
Timir[timers]=0;
}
void StartTimers(unsigned char timers){
Timir[timers]=0xFFFD; //65533 2ms что бы дошло до нужного места программы
}
void servic_timer(void){
unsigned char i=0;
for (i=0; i<MAX_TIMERS; i++) {
Timir[i]++;
//-----Доработка что бы таймеры не обнулился после переполнения-----
if(Timir[i]>0xFFFA){ //65530 (5 едениц запас)
Timir[i]=0xFFFA;
}
}
}
Спойлер
Код: Выделить всё
#ifndef service_timer_h_
#define service_timer_h_
//******************************************************************************
// Секция include: здесь подключаются заголовочные файлы используемых модулей
//******************************************************************************
#include "Aplication.h"
//******************************************************************************
// Секция определения макросов
//******************************************************************************
enum{
TEST1,
TEST2,
};
#define MAX_TIMERS 3
//******************************************************************************
// Секция определения глобальных переменных
//******************************************************************************
extern volatile unsigned int Timir[MAX_TIMERS];
//******************************************************************************
//*******************Секция прототипов функций
//******************************************************************************
unsigned int GetTimers(unsigned char timers);
void ResetTimers(unsigned char timers);
void StartTimers(unsigned char timers);
void servic_timer(void);
#endif /* service_timer_h_*/
//******************************************************************************
// ENF OF FILE
//******************************************************************************
Так вот проблема в том что в одном проекте может быть 5 счётчиков в другом 10 в третьем 25
по этому файл service_timer.h от проекта к проекту меняется и приходится копировать его, что я думаю не совсем правильно.
А создавать ещё один файл который содержит только enum тоже как-то не то.
Как в таком случае создать библиотеку? (единую для всех проектов)
и где и как лучше разместить различия?
вообще-то в Си "библиотекой" принято называть специальным образом скомпилированный объектный файл. а когда вы работаете с исходниками, это и называется "исходник", библиотекой это называем мы некорректно.
так вот, настоящая библиотека, например, math, собирается единожды и затем уже никак не позволяет вам менять макросы, которые были при ее сборке определены, хотя в math.h у вас эти макросы перечислены и вроде бы даже доступны для изменения. эти изменения никак не повлияют на библиотеку, только на ваши исходники.
поэтому если вы все-таки будете работать с исходниками, в вашем подходе нет никакого криминала, более того, копирование исходников - это чуть ли не единственно корректный подход в этом случае!
но если уж вы совсем щепитильно хотите следить за неизменностью "основного" кода вашей "библиотеки", можете сделать что-то вроде этого:то есть если "где-то раньше" не определен макрос MAX_TIMERS, будет использовано дефолтное значение, а если определено - то оно и будет использовано. таким образом в своем проекте вы получаете право делать любое количество таймеров, не влезая в "основной код либы".
так вот, настоящая библиотека, например, math, собирается единожды и затем уже никак не позволяет вам менять макросы, которые были при ее сборке определены, хотя в math.h у вас эти макросы перечислены и вроде бы даже доступны для изменения. эти изменения никак не повлияют на библиотеку, только на ваши исходники.
поэтому если вы все-таки будете работать с исходниками, в вашем подходе нет никакого криминала, более того, копирование исходников - это чуть ли не единственно корректный подход в этом случае!
но если уж вы совсем щепитильно хотите следить за неизменностью "основного" кода вашей "библиотеки", можете сделать что-то вроде этого:
Код: Выделить всё
#ifndef MAX_TIMERS
#define MAX_TIMERS DEFAULT_MAX_TIMERS
#endifесли рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
не могу понять откуда берется этот указатель *string и *data (если это конечно указатель на массив )?
Код: Выделить всё
// Функция вывода строки на LCD
void lcd_string(unsigned char command, char *string)
{
lcd_com(0x0C);
lcd_com(command);
while(*string != '\0')
{ lcd_data(*string);
string++;
}
}Спойлер
Код: Выделить всё
// Функция чтения данных по шине
uint8_t I2CReadByte(uint8_t *data,uint8_t ack)
{
if(ack) // Устанавливаем подтверждение
{
// Возвращаем подтверждение после приема
TWCR |= (1 << TWEA);
}
else
{
// Возвращаем неподтверждение после приема
// Ведомое устройство не получает больше данных
// обычно используется для распознования последнего байта
TWCR &= ~(1 << TWEA);
}
// Разрешение приема данных после сброса TWINT
TWCR |= (1 << TWINT);
while(!(TWCR & (1 << TWINT))); // Ожидание установки флага TWINT
// Проверка статуса
if((TWSR & 0xF8) == 0x58 || (TWSR & 0xF8) == 0x50)
{
// Прием данных и возвращение подтверждения
// или
// Прием данных и возвращение неподтверждения
*data = TWDR; // Читаем данные
return 1;
}
else
return 0; // Ошибка
}Спойлер
Код: Выделить всё
#include <avr/io.h>
#include <util/delay.h>
// Функция инициализация шины TWI
void I2CInit(void)
{
// настройка TWI модуля
TWBR = 2;
TWSR = (1 << TWPS1)|(1 << TWPS0); // Предделитель на 64
TWCR |= (1 << TWEN); // Включение модуля TWI
}
void I2CStart(void)
{
// Передача условия СТАРТ
TWCR = (1 << TWINT)|(1 << TWEN)|(1 << TWSTA);
// Ожидание установки флага TWINT
while(!(TWCR & (1 << TWINT)));
}
void I2CStop(void)
{
TWCR = (1 << TWINT)|(1 << TWEN)|(1 << TWSTO); // Передача условия СТОП
while(TWCR & (1 << TWSTO)); // Ожидание завершения передачи условия СТОП
}
// Функция записи данных по шине
uint8_t I2CWriteByte(uint8_t data)
{
TWDR = data; // Загрузка данных в TWDR
TWCR = (1 << TWEN)|(1 << TWINT); // Сброс флага TWINT для начала передачи данных
while(!(TWCR & (1 << TWINT))); // Ожидание завершения передачи
// Проверка статуса
if((TWSR & 0xF8) == 0x18 || (TWSR & 0xF8) == 0x28 || (TWSR & 0xF8) == 0x40)
{
// Если адрес DS1307, биты R/W и данные переданы
// и получено подтверждение
return 1;
}
else
return 0; // ОШИБКА
}
// Функция чтения данных по шине
uint8_t I2CReadByte(uint8_t *data,uint8_t ack)
{
if(ack) // Устанавливаем подтверждение
{
// Возвращаем подтверждение после приема
TWCR |= (1 << TWEA);
}
else
{
// Возвращаем неподтверждение после приема
// Ведомое устройство не получает больше данных
// обычно используется для распознования последнего байта
TWCR &= ~(1 << TWEA);
}
// Разрешение приема данных после сброса TWINT
TWCR |= (1 << TWINT);
while(!(TWCR & (1 << TWINT))); // Ожидание установки флага TWINT
// Проверка статуса
if((TWSR & 0xF8) == 0x58 || (TWSR & 0xF8) == 0x50)
{
// Прием данных и возвращение подтверждения
// или
// Прием данных и возвращение неподтверждения
*data = TWDR; // Читаем данные
return 1;
}
else
return 0; // Ошибка
}
// Функция чтения данных из DS1307
uint8_t DS1307Read(uint8_t address,uint8_t *data)
{
uint8_t res; // Результат
I2CStart(); // СТАРТ
res = I2CWriteByte(0b11010000); // адрес DS1307 + бит W
if(!res) return 0; // ОШИБКА
// Передача адреса необходимого регистра
res = I2CWriteByte(address);
if(!res) return 0; // ОШИБКА
I2CStart(); // Повторный СТАРТ
res = I2CWriteByte(0b11010001); // адрес DS1307 + бит R
if(!res) return 0; // ОШИБКА
// Чтение данных с неподтверждением
res = I2CReadByte(data,0);
if(!res) return 0; // ОШИБКА
I2CStop(); // СТОП
return 1;
}
// Функция записи данных в DS1307
uint8_t DS1307Write(uint8_t address,uint8_t data)
{
uint8_t res; // Результат
I2CStart(); // СТАРТ
res = I2CWriteByte(0b11010000); // адрес DS1307 + бит W
if(!res) return 0; // ОШИБКА
// Передача адреса необходимого регистра
res = I2CWriteByte(address);
if(!res) return 0; // ОШИБКА
res = I2CWriteByte(data); // Запись данных
if(!res) return 0; // ОШИБКА
I2CStop(); // СТОП
return 1;
}
// Функции работы с LCD
#define RS PD0
#define EN PD2
// Функция передачи команды
void lcd_com(unsigned char p)
{
PORTD &= ~(1 << RS); // RS = 0 (запись команд)
PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p & 0xF0); // старший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p << 4); // младший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
}
// Функция передачи данных
void lcd_data(unsigned char p)
{
PORTD |= (1 << RS)|(1 << EN); // RS = 1 (запись данных), EN - 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p & 0xF0); // старший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
PORTD |= (1 << EN); // EN = 1 (начало записи команды в LCD)
PORTD &= 0x0F; PORTD |= (p << 4); // младший нибл
_delay_us(100);
PORTD &= ~(1 << EN); // EN = 0 (конец записи команды в LCD)
_delay_us(100);
}
// Функция вывода строки на LCD
void lcd_string(unsigned char command, char *string)
{
lcd_com(0x0C);
lcd_com(command);
while(*string != '\0')
{ lcd_data(*string);
string++;
}
}
// Функция вывода переменной
void lcd_num_to_str(unsigned int value, unsigned char nDigit)
{
switch(nDigit)
{
case 4: lcd_data((value/1000)+'0');
case 3: lcd_data(((value/100)%10)+'0');
case 2: lcd_data(((value/10)%10)+'0');
case 1: lcd_data((value%10)+'0');
}
}
// Функция инициализации LCD
void lcd_init(void)
{
PORTD = 0x00;
DDRD = 0xFF;
_delay_ms(50); // Ожидание готовности ЖК-модуля
// Конфигурирование четырехразрядного режима
PORTD |= (1 << PD5);
PORTD &= ~(1 << PD4);
// Активизация четырехразрядного режима
PORTD |= (1 << EN);
PORTD &= ~(1 << EN);
_delay_ms(5);
lcd_com(0x28); // шина 4 бит, LCD - 2 строки
lcd_com(0x08); // полное выключение дисплея
lcd_com(0x01); // очистка дисплея
_delay_us(100);
lcd_com(0x06); // сдвиг курсора вправо
lcd_com(0x0C); // включение дисплея, курсор не видим
}
int main(void)
{
_delay_ms(100);
DDRC = 0x00;
PORTC = 0xFF;
lcd_init(); // Инициализация LCD
I2CInit(); // Инициализация шины I2C
// Запускаем ход часов
uint8_t temp;
DS1307Read(0x00,&temp);
temp &= ~(1 << 7); // обнуляем 7 бит
DS1307Write(0x00,temp);
while(1)
{
unsigned char hour, minute, second, temp;
// Читаем данные и преобразуем из BCD в двоичную систему
DS1307Read(0x00,&temp); // Чтение регистра секунд
second = (((temp & 0xF0) >> 4)*10)+(temp & 0x0F);
DS1307Read(0x01,&temp); // Чтение регистра минут
minute = (((temp & 0xF0) >> 4)*10)+(temp & 0x0F);
DS1307Read(0x02,&temp); // Чтение регистра часов
hour = (((temp & 0xF0) >> 4)*10)+(temp & 0x0F);
lcd_string(0x81, "«acГ Ѕa DS1307");
lcd_string(0xC4, " : : ");
lcd_com(0xC4);
lcd_num_to_str(hour, 2); // Выводим на экран часы
lcd_com(0xC7);
lcd_num_to_str(minute, 2); // Выводим на экран минуты
lcd_com(0xCA);
lcd_num_to_str(second, 2); // Выводим на экран секунды
if((PINC & (1 << PC0))==0) // Если нажата кнопка
{
while((PINC & (1 << PC0))==0){} // Ждем отпускания кнопки
hour++; // Увеличиваем часы на 1
if(hour > 23) hour = 0;
// Преобразуем из двоичной системы в BCD и записываем в DS1307
uint8_t temp;
temp = ((hour/10) << 4)|(hour%10);
DS1307Write(0x02, temp);
_delay_ms(100);
}
if((PINC & (1 << PC1))==0) // Если нажата кнопка
{
while((PINC & (1 << PC1))==0){} // Ждем отпускания кнопки
minute++; // Увеличиваем минуты на 1
if(minute > 59) minute = 0;
// Преобразуем из двоичной системы в BCD и записываем в DS1307
uint8_t temp;
temp = ((minute/10) << 4)|(minute%10);
DS1307Write(0x01, temp);
_delay_ms(100);
}
}
} не могу понять, что вы не можете понять?mastech писал(а):не могу понять откуда берется этот указатель *string и *data (если это конечно указатель на массив )?
mastech писал(а):void lcd_string(unsigned char command, char *string)
{
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
string (в функции lcd_string) - это указатель на char, data (в функции I2CReadByte) - указатель на uint8_t. Оно же прямо там и написано.
зачем объявлять указатель и не указывать не на одну переменную? и почему не дать просто имя?
в моем понимании чтоб *string использовать надо где то указать на какую переменную он должен указывать.
unsigned char i;
unsigned char *string;
string=&i;
или в функциях другие правила указателя?
в моем понимании чтоб *string использовать надо где то указать на какую переменную он должен указывать.
unsigned char i;
unsigned char *string;
string=&i;
или в функциях другие правила указателя?
Последний раз редактировалось mastech Ср июл 15, 2015 14:11:25, всего редактировалось 1 раз.


