Урок 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 с адаптером
Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)
Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)
Здравствуйте меня нужно коды ваши вашей уроки селности
Так меня читать удобна
Мне нужно на ценности вашей сходный kод для изучения так мне удобно изучать программирование