Урок 39
Часть 2
Акселерометр LSM6DS3
Продолжаем работать с подключением датчика.
В прошлой части занятия мы подключили плату с датчиком к отладочной плате с контроллером, а также подключили переходник USART для мониторинга показаний датчика, также создали проект, инициализировали USART и написали код для проверки данного интерфейса, но пока его не проверили.
Поэтому теперь мы соберём проект, прошьём контроллер, перед этим не забыв нажать кнопку Connect в терминальной программе. Должно после прошивки получиться вот так
Если оно так, то мы на правильном пути и можно двигаться дальше.
Теперь продолжаем работать непосредственно с шиной I2C. Это мы тоже умеем. Чтобы воспользоваться данной шиной, из проекта, например по работе с часовой микросхемой MyClock1307LED, скопируем и подключим в наш проект файлы twi.h и twi.c. Также подключим данную библиотеку в файле main.h
#include «usart.h»
#include «twi.h»
Работа с шиной I2C на контроллере Atmega328 вообще ничем не отличается от работы с данной шиной на контроллере Atmega8, поэтому проект у нас должен будет нормально собраться.
Вызовем инициализацию I2C в main()
I2C_Init();//инициализируем TWI
USART_Init (16); //115200
Также есть ещё одна тонкость. Мы ещё с двух ножек I2C должны подключить подтягивающие резисторы на шину питания, но я этого делать не стал и подключил их программно. Вы можете поступить по другому и припаять их физически. Также в ваших модулях с датчиком они могут уже быть. Вообщем, напишем функцию инициализации порта и вызовем её в main(). Заодно включим на выход ножку, к которой подключен красный светодиод, чтобы с помощью него следить за ошибками
//—————————————————
void port_ini(void)
{
DDRC&=~0b00110000;
PORTC|=0b00110000;
DDRB|=(1<<PORTB5);
}
//—————————————————
int main(void)
{
port_ini();
Также для нашей шины I2C мы должны рассчитать скорость. Её мы оставим 100 кГц, но кварцевый резонатор у нас 16 МГц, и воспользовавшись таблицей расчета TWBR, мы вычислим его значения и внесем изменения в функции в файле twi.c
void I2C_Init (void)
{
TWBR=0x48;//скорость передачи (при 16 мгц получается 100 кгц)
}
Создадим и подключим ещё файлы будущей библиотеки для работы с датчиком lsm6ds3.h и lsm6ds3.c, а также подключим lsm6ds3.h в main.h
#include «twi.h»
#include «lsm6ds3.h»
Также подключим его и в файле lsm6ds3.c
#include «lsm6ds3.h»
//———————————————
Подключим в файле lsm6ds3.h все наши интерфейсы, макросы для ножки светодиода, а также из одноименного файла из проекта для контроллера stm скопируем макросы для регистров акселерометра
#ifndef LSM6DS3_H_
#define LSM6DS3_H_
//—————————————-
#include «main.h»
#include «usart.h»
#include «twi.h»
//—————————————-
#define LD_ON PORTB|=(1<<PORTB5)
#define LD_OFF PORTB&=~(1<<PORTB5)
//————————————————
#define LSM6DS3_ACC_GYRO_CTRL1_XL 0X10
#define LSM6DS3_ACC_GYRO_CTRL3_C 0X12
#define LSM6DS3_ACC_GYRO_FIFO_CTRL5 0X0A
#define LSM6DS3_ACC_GYRO_CTRL9_XL 0X18
//————————————————
#define LSM6DS3_ACC_GYRO_IF_INC_DISABLED 0x00
#define LSM6DS3_ACC_GYRO_IF_INC_ENABLED 0x04
#define LSM6DS3_ACC_GYRO_IF_INC_MASK 0x04
//————————————————
#define LSM6DS3_ACC_GYRO_BDU_CONTINUOS 0x00
#define LSM6DS3_ACC_GYRO_BDU_BLOCK_UPDATE 0x40
#define LSM6DS3_ACC_GYRO_BDU_MASK 0x40
//————————————————
#define LSM6DS3_ACC_GYRO_FIFO_MODE_BYPASS 0x00
#define LSM6DS3_ACC_GYRO_FIFO_MODE_FIFO 0x01
#define LSM6DS3_ACC_GYRO_FIFO_MODE_STREAM 0x02
#define LSM6DS3_ACC_GYRO_FIFO_MODE_STF 0x03
#define LSM6DS3_ACC_GYRO_FIFO_MODE_BTS 0x04
#define LSM6DS3_ACC_GYRO_FIFO_MODE_DYN_STREAM 0x05
#define LSM6DS3_ACC_GYRO_FIFO_MODE_DYN_STREAM_2 0x06
#define LSM6DS3_ACC_GYRO_FIFO_MODE_BTF 0x07
#define LSM6DS3_ACC_GYRO_FIFO_MODE_MASK 0x07
//————————————————
#define LSM6DS3_ACC_GYRO_ODR_XL_POWER_DOWN 0x00
#define LSM6DS3_ACC_GYRO_ODR_XL_13Hz 0x10
#define LSM6DS3_ACC_GYRO_ODR_XL_26Hz 0x20
#define LSM6DS3_ACC_GYRO_ODR_XL_52Hz 0x30
#define LSM6DS3_ACC_GYRO_ODR_XL_104Hz 0x40
#define LSM6DS3_ACC_GYRO_ODR_XL_208Hz 0x50
#define LSM6DS3_ACC_GYRO_ODR_XL_416Hz 0x60
#define LSM6DS3_ACC_GYRO_ODR_XL_833Hz 0x70
#define LSM6DS3_ACC_GYRO_ODR_XL_1660Hz 0x80
#define LSM6DS3_ACC_GYRO_ODR_XL_3330Hz 0x90
#define LSM6DS3_ACC_GYRO_ODR_XL_6660Hz 0xA0
#define LSM6DS3_ACC_GYRO_ODR_XL_13330Hz 0xB0
#define LSM6DS3_ACC_GYRO_ODR_XL_MASK 0xF0
//————————————————
#define LSM6DS3_ACC_GYRO_FS_XL_2g 0x00
#define LSM6DS3_ACC_GYRO_FS_XL_16g 0x04
#define LSM6DS3_ACC_GYRO_FS_XL_4g 0x08
#define LSM6DS3_ACC_GYRO_FS_XL_8g 0x0C
#define LSM6DS3_ACC_GYRO_FS_XL_MASK 0x0C
//————————————————
#define LSM6DS3_ACC_GYRO_XEN_XL_MASK 0x08
#define LSM6DS3_ACC_GYRO_YEN_XL_MASK 0x10
#define LSM6DS3_ACC_GYRO_ZEN_XL_MASK 0x20
#define LSM6DS3_ACC_GYRO_XEN_XL_ENABLED 0x08
#define LSM6DS3_ACC_GYRO_YEN_XL_ENABLED 0x10
#define LSM6DS3_ACC_GYRO_ZEN_XL_ENABLED 0x20
//————————————————
#define LSM6DS3_ACC_GYRO_OUTX_L_XL 0X28
#define LSM6DS3_ACC_GYRO_OUTX_H_XL 0X29
#define LSM6DS3_ACC_GYRO_OUTY_L_XL 0X2A
#define LSM6DS3_ACC_GYRO_OUTY_H_XL 0X2B
#define LSM6DS3_ACC_GYRO_OUTZ_L_XL 0X2C
#define LSM6DS3_ACC_GYRO_OUTZ_H_XL 0X2D
//————————————————
#endif /* LSM6DS3_H_ */
В файле lsm6ds3.c начнем писать функцию инициализации датчика
#include «lsm6ds3.h»
//———————————————
void Accel_Ini(void)
{
}
Первым делом добавим задержку для того, чтобы перед инициализацией датчик успел нормально включиться и прошел самотестирование
void Accel_Ini(void)
{
_delay_ms(500);
Также все мы помним, чтобы инициализировать любой датчик и убедиться, что мы работаем именно с таким датчиком, нам необходимо считать его идентификатор
Создадим функцию для чтения идентификатора, расположим её выше функции инициализации, чтобы легче было вызывать без прототипов
//———————————————
unsigned char Accel_ReadID(void)
{
}
//———————————————
void Accel_Ini(void)
Теперь нам нужно будет написать функцию чтения данных вообще по шине I2C неопределённой длины из датчика. Также создадим пока каркас данной функции
//———————————————
void I2Cx_ReadData(unsigned char Addr, unsigned char Reg, unsigned char sz, unsigned char* value)
{
}
//———————————————
unsigned char Accel_ReadID(void)
Во входных аргументах данной функции у нас будет адрес устройства, адрес регистра, количество байтов, которые мы будем считывать и указатель на участок памяти, в которые будут укладываться эти байты. Для этого создадим глобальную переменную в данном файле
#include «lsm6ds3.h»
//———————————————
unsigned char read_buf[10]={0};
Прекрасно зная, как именно читать байты из шины I2C и помня о том. что последний считанный байт мы не подтверждаем, а генерируем в этот момент высокое состояние шины, напишем тела функции приёма байтов из шины
void I2Cx_ReadData(unsigned char Addr, unsigned char Reg, unsigned char sz, unsigned char* value)
{
unsigned char i=sz,n=0;
I2C_StartCondition(); //отправим условие START
I2C_SendByte(Addr);//передаем адрес устройства и бит записи (0)
I2C_SendByte(Reg);//передаем адрес регистра
I2C_StartCondition(); //отправим условие START
I2C_SendByte(Addr|0x01);//передаем адрес устройства и бит чтения (1)
while(1)
{
if(i==1) break;
value[n]=I2C_ReadByte();
i—; n++;
}
value[sz-1] = I2C_ReadLastByte(); //прочитаем последний байт
I2C_StopCondition(); //отправим условие STOP
}
Уточним адрес устройства, а также регистр и идентификатор в технической документации на датчик
Воспользовавшись функцией чтения данных из шины, напишем тело функции для считывания идентификатора
unsigned char Accel_ReadID(void)
{
unsigned char ctrl=0;
I2Cx_ReadData(0xD4,0x0F,1,read_buf);
return ctrl;
}
Напишем в самом верху файла функцию срабатывания красного светодиода на ошибку
unsigned char read_buf[10]={0};
//———————————————
void Error(void)
{
LD_ON;
}
Теперь вызовем функцию чтения идентификатора в функции инициализации датчика
void Accel_Ini(void)
{
_delay_ms(500);
Accel_ReadID();
if(read_buf[0]!=0x69) Error();
}
Добавим в заголовочный файл прототип функции инициализации
#define LSM6DS3_ACC_GYRO_OUTZ_H_XL 0X2D
//—————————————-
void Accel_Ini(void);
//—————————————-
Вызовем функцию инициализации датчика в main() и удалим код отправки тестовой строки в USART
USART_Init (16); //115200
Accel_Ini();
while (1)
Соберём код, прошьём контроллер, и, если у нас светодиод не загорится, значит мы считали правильный идентификатор и мы работаем и общаемся по шине I2C именно с тем датчиком.
Это очень хорошо. Дальнейшую инициализацию мы продолжим в следующей части нашего урока.
Предыдущая часть Программирование МК AVR Следующая часть
Техническая документация:
Документация на оценочную плату
Приобрести плату Atmega 328p Pro Mini можно здесь.
Приобрести программатор USBASP USBISP с адаптером можно здесь USBASP USBISP 3.3 с адаптером
Смотреть ВИДЕОУРОК (нажмите на картинку)
Здравствуйте меня нужно коды ваши вашей уроки селности
Так меня читать удобна
Мне нужно на ценности вашей сходный kод для изучения так мне удобно изучать программирование