/*!
* @mainpage
*
* Опции для компиляции:
*
* 1. avr-gcc сс opts:
* @code
* -mmcu={?} # какой МК?
* -DF_CPU={?} # какая частота тактирования?
* -Os # оптимизация по размеру
* -x c++ # компиляция в режиме Си++
* -g # включить отладочную информацию в выходной elf
* -ffunction-sections -fdata-sections # прочие полезные ключи
* @endcode
*
* 2. avr-gcc linker opts:
* @code
* -mmcu={?}
* -Os
* -g
* -Wl,--gc-sections
* -Wl,--relax
* -Wl,-Map=main.map # map-файл
* @endcode
*/
/*!
*/
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <util/delay.h>
// назначение определений для удобства работы с периферией
#define PORTOUT PORTB
#define DDROUT DDRB
#define PINOUT PINB
#define MOTOR_F PB5
#define MOTOR_B PB3
#define TURN_L PB4
#define TURN_R PB2
#define IRLED PB1
#define PORTIN PORTD
#define DDRIN DDRD
#define PININ PIND
#define LIGHT_R PD0
#define LIGHT_L PD1
#define BUMPER_F PD3
#define SBI(port,bit) port |= (1<<(bit))
#define CBI(port,bit) port &= ~(1<<(bit))
// #define outb(port,bit) port = bit
//<- отказаться! <-Почему?
//<- а смысл истользовать устаревший макрос?, тем более что он ни где не используется
//! Возможные режимы движения
typedef enum {STOP=0, F, FR, FL, B, BR, BL} direction_t;
const unsigned int TIME=1;
// #define F_CPU 4000000
//<- задать это ключем при компиляции -DF_CPU=4000000UL , это впринципе можно и так оставить?
//<- нет это должно быть указано в Makefile, иначе _delay_(.*) не будет работать правильно
/*!
* таблица вероятностей для выбора направления движения
* исходя из текущего направления движения
*/
unsigned char p[7][7] = {
{14, 43, 57, 71, 7, 100, 100},
{7, 43, 71, 100, 100, 100, 100},
{7, 50, 93, 100, 100, 100, 100},
{7, 50, 57, 100, 100, 100, 100},
{29, 29, 29, 29, 57, 79, 100},
{36, 36, 36, 36, 71, 93, 100},
{36, 36, 36, 36, 71, 79, 100},
};
//! текущее направление движения
direction_t this_move;
//unsigned char this_move;
/*!
* Включение комбинации моторов для движения в заданном направлении
*/
void go(direction_t direction){
switch (direction) {
case STOP:
CBI(PORTOUT, MOTOR_F);
CBI(PORTOUT, MOTOR_B);
CBI(PORTOUT, TURN_R);
CBI(PORTOUT, TURN_L);
break;
case F:
SBI(PORTOUT, MOTOR_F);
CBI(PORTOUT, MOTOR_B);
CBI(PORTOUT, TURN_R);
CBI(PORTOUT, TURN_L);
break;
case FR:
SBI(PORTOUT, MOTOR_F);
CBI(PORTOUT, MOTOR_B);
SBI(PORTOUT, TURN_R);
CBI(PORTOUT, TURN_L);
break;
case FL:
SBI(PORTOUT, MOTOR_F);
CBI(PORTOUT, MOTOR_B);
CBI(PORTOUT, TURN_R);
SBI(PORTOUT, TURN_L);
break;
case B:
CBI(PORTOUT, MOTOR_F);
SBI(PORTOUT, MOTOR_B);
CBI(PORTOUT, TURN_R);
CBI(PORTOUT, TURN_L);
break;
case BR:
CBI(PORTOUT, MOTOR_F);
SBI(PORTOUT, MOTOR_B);
SBI(PORTOUT, TURN_R);
CBI(PORTOUT, TURN_L);
break;
case BL:
CBI(PORTOUT, MOTOR_F);
SBI(PORTOUT, MOTOR_B);
CBI(PORTOUT, TURN_R);
SBI(PORTOUT, TURN_L);
break;
}
}
/*!
* Выбор направления движения в следующем шаге по таблице вероятностей
*/
direction_t next_move(void){
unsigned char pp,
direction_t i;
// получаем случайное число 0..99
pp = rand()/327;
// ищем соответствие в таблице вероятностей
for (i=STOP; i < BL+1; i++) {
if (p[this_move][i] > pp)
break;
}
this_move = i; // записываем новое полученное направление как текущее
return(i);
}
/*!
* "Случайное блуждание"
*/
inline void walk(void){
// этот цикл организует "свободное блуждание" пока
// нет сигнала ни от одного из датчиков освещенности
while ( (bit_is_set(PININ, LIGHT_R)) && (bit_is_set(PININ, LIGHT_L)) ) {
// получаем следующее направление движения и
go(next_move());
_delay_ms(250);
}
for (int ii=0; ii < 10; ii++) {
_delay_loop_1(TIME);
CBI(PORTOUT, IRLED); // включаем ИК светодиод
_delay_loop_1(TIME);
SBI(PORTOUT, IRLED); // выкл ИК светодиод
}
int count=0;
for (int u=0; u < 14; u++){
// если есть сигнал на Ик приемнике
if (bit_is_clear(PININ, BUMPER_F)) {
count++;
if (count == 14) {
if (this_move == FR)
go(BL);
if (this_move == FL)
go(BR);
else
go(B);
// дай угадаю, не работает?
_delay_ms(250);
_delay_ms(250);
this_move = B;
}
}
}
// этот цикл организует движение на свет, пока
// есть сигнал хотя бы от одного из датчиков освещенности
while ( (bit_is_clear(PININ, LIGHT_R)) || (bit_is_clear(PININ, LIGHT_L)) ) {
if ( (bit_is_clear(PININ, LIGHT_R)) && (bit_is_clear(PININ, LIGHT_L)) )
go(F);
else { //<- без этих скобок потенциальное место ошибок
if (bit_is_clear(PININ, LIGHT_R))
go(FR);
else
if (bit_is_clear(PININ, LIGHT_L))
go(FL);
}
}
}
/*!
* Главная программа
*/
int main(void)
{
DDROUT = 0xff;
PORTOUT = 0x00;
DDRIN = 0x00;
PORTIN = 0xff;
// запускаем главный цикл
while(true)
walk();
return 0;
}