Администрация форума не несёт ответственности за достоверность информации и оставляет за собой право редактировать или в особых случаях даже удалять посты без предупреждения. Спасибо за понимание.

Программирование ATMEL в BASCOM.

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Программирование ATMEL в BASCOM. » Не пора ли нам попробовать ARM? » (Пример работы с АЦП и USB) Чтение температуры со встроенного датчика


(Пример работы с АЦП и USB) Чтение температуры со встроенного датчика

Сообщений 1 страница 15 из 15

1

В STM32 есть встроенный датчик температуры, (по видимому состоящий из двух диодов, включенных последовательно), который подключен к одному из каналов АЦП. Что-то похожее есть в некоторых моделях МК AVR.
Датчик не калиброванный и с одной и той же прошивкой, может показывать разную температуру в различных экземплярах МК. Поэтому для точных измерений (без калибровки) он не подходит, но как пример работы с АЦП подойдет.
В даташите написано про датчик не очень много. Это вся информация (поместилась на половине страницы даташита).

http://s7.uploads.ru/zrK8o.png

Для расчета температуры служит формула.

Temperature = (V_25-V_sense)/Avg_Slope + 25

Где V_25 и Avg_Slope это данные из даташита, а V_sense - измеренное напряжение на датчике температуры. Все напряжения должны быть в вольтах. Температура будет рассчитана в градусах по Цельсию.
После расчета данные будут выводится с МК через USB и отобраюатся в компьютерной программе. Почему так? Мне так проще, а заодно узнаем как работать с USB.

Создаем проекты EmBlocks и STM32CubeMX как писал ранее.
Теперь в STM32CubeMX настроим периферию МК. Нужно выбрать тактовый генератор, настроить тактиование отдельных модулей МК, а так же сконфигурировать АЦП и USB.
На вкладке "Pinout" начнем по порядку сверху вниз конфигурировать модули. Открываем раздел ADC1 и выбираем канал датчика температуры.

http://s6.uploads.ru/t/z4Zf5.png

Далее в разделе RCC нужно включить внешний высокочастотный резонатор.

http://s5.uploads.ru/ZnSzJ.png

Дальше в разделе USB нужно включить этот модуль.

http://s8.uploads.ru/xVJ5X.png

Теперь нужно в разделе "USB Device" выбрать тип USB устройства. Нам нужен HID.

http://sg.uploads.ru/eRv70.png

Скриншот всех изменений, который были сделаны.

http://s2.uploads.ru/t/3ezki.png

Теперь переходим на вкладку "Clock configuration".
Задача проста. Настроить тактирование таким образом чтобы ядро и модули МК тактировались от внешнего резонатора. На модуль USB поступала частота 48 МГц, а так же на других модулях частота на была больше или меньше допустимой (подсвечивается красным).
Должно получится примерно так.

http://s9.uploads.ru/t/gMnHu.png

Теперь переходим на вкладку "Сonfiguration", где можно настроить выбранные модули.

http://s3.uploads.ru/t/3HwjC.png

Сначала настроим АЦП. Кликаем по кнопке "ADC1".
Откроется окно. Настраиваем все также.

http://s3.uploads.ru/t/OMrv6.png

Теперь кликаем по кнопке "USB_Device". Откроется окно.

http://s8.uploads.ru/t/2wxZ8.png

То что находится в разделе "Basic parameters" изменять не нужно - подойдут параметры по умолчанию.
Параметр USBD_CUSTOM_HID_REPORT_DESC_SIZE это размер дескриптора HID_Report (о нем поговорим позже). Его размер в данной программе 33 байта.
Параметр USBD_CUSTOMHID_OUTREPORT_BUF_SIZE определяет размер буфера приема данных из компьютера.

Переходим на вкладку "Device descriptor". Настраиваем как на скриншоте.

http://sh.uploads.ru/t/9txuG.png

Сохраняем настройки нажав на кнопку OK.

Теперь генерируем код и экспортируем его в EmBlocks.

В EmBlocks открываем файл "usbd_custom_hid_if.c", находящийся в папке Sources\Src проекта.

http://s7.uploads.ru/t/mWSGZ.png

В нем находим массив CUSTOM_HID_ReportDesc_FS и вставляем в него код HID дескриптора. Должно получится.

Код:
__ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
{
  /* USER CODE BEGIN 0 */
    0x06 , 0x00 , 0xFF,             // Usage_page(vendor Defined Page 1)
    0x09 , 0x01,                    // Usage(vendor Usage 1)
    0xA1 , 0x02,                    // Collection(logical)
// Описание конечной точки, типа Input
    0x09 , 0x01,                    // Usage(pointer)
    0x15 , 0x00,                    // Logical_minimum(0)
    0x25 , 0xFF,                    // Logical_maximum(255)
    0x75 , 0x08,                    // Report_size(8)
    0x95 , 0x02,                    // Report_count(2)
    0x81 , 0x02,                    // Input( , Var , Abs)
// Описание конечной точки, типа Output
    0x09 , 0x01,                    // Usage(pointer)
    0x15 , 0x00,                    // Logical_minimum(0)
    0x26 , 0xFF , 0,                // Logical_maximum(255)
    0x75 , 0x08,                    // Report_size(8)
    0x95 , 0x02,                    // Report_count(2)
    0x91 , 0x02,                    // Output(data , Var , Abs)
  /* USER CODE END 0 */
  0xC0    /*     END_COLLECTION	             */

};

Сохраняем файл.
Теперь открываем файл main.c , находящийся в папке Sources\Src проекта.
В него нужно добавить идентификатор USB

Код:
USBD_HandleTypeDef  *hUsbDevice_0;

а также константы из даташита, для датчика температуры.

Код:
#define tV_25   1.34f      // Напряжение (в вольтах) на датчике при температуре 25 °C.
#define tSlope  0.0043f    // Изменение напряжения (в вольтах) при изменении температуры на градус.
#define Vref    3.3f       // Образцовое напряжение АЦП (в вольтах).

Теперь в функции main нужно до цикла while добавить объявление переменных.

Код:
    int16_t Result=0;
    float temp;

а в цикле while, код чтения данных с АЦП, преобразования его в температуру и передачи в компьютер.

Код:
    HAL_Delay(1000);       // Задержка 1000 мс.
    HAL_ADC_Start(&hadc1); // Запуск АЦП.
    if (HAL_ADC_PollForConversion(&hadc1, 100) == HAL_OK) // Ожидание завершения преобразования.
    {
        Result = HAL_ADC_GetValue(&hadc1); // Считывание с АЦП.

        temp = (float) Result/4096*Vref;   // Напряжение в вольтах на датчике.
        temp = (tV_25-temp)/tSlope + 25;   // Температура в градусах.
        temp = temp * 16;                  // Приводим данные к формату DS18B20.
        Result = (int16_t) temp;

        USBD_CUSTOM_HID_SendReport(hUsbDevice_0, &Result, 2); // Передача данных компьютеру.
    }
    HAL_ADC_Stop(&hadc1); // Остановка АЦП.

Программа написана. Как видим, большинство кода было сгенерировано программной STM32CubeMX. Нам же понадобилось добавить HID_Report, пару переменных и констант, а также несколько строк кода, считывающих температуру с АЦП и передающих ее в компьютер.
Программа написана так, что работает с компьютерной программой из другого проекта.

Скриншот программы.

http://s0.uploads.ru/sjwfv.png

Судя по начальной температуре, и по той что измерена через несколько минут работы, температура кристалла на 8 градусов выше температуры воздуха.

Файлы (программа для компьютера с исходником в папке PC). http://pure-basic.narod.ru/forum_files/ … rmoADC.zip
Разработка программы МК велась в EmBitz 0.42 и STM32CubeMX 4.14.0.

+2

2

Аналогичная программа на mikroBasic. Скажу сразу, код нормально не заработал. С АЦП читается не то что должно (не то что в программе на Си), но все же решил его выложить. Может у кого будут идеи почему работает не так как должно.

Для начала создаем папку для проекта, в которую нужно скопировать файл USBdsc.mbas, который можно найти в папке с примерами.

Examples\ST\Development Systems\EasyMx PRO v7 for STM32 ARM\USB\HID_Read_Write_Interrupt\

Он содержит дескрипторы и нужен для USB HID.

Создаем проект (меню Project пункт "New Project").

http://s8.uploads.ru/t/Vljwf.png

Переходим на следующую страницу, где можно добавить файлы в проект. Добавляем USBdsc.mbas.

http://s2.uploads.ru/t/72EZL.png

Дальше нужно решить добавить все библиотеки или нет. Особого значения не имеет, т. к. потом можно это изменить (меню View пункт "Library Manager"). Для этого проекта достаточно библиотек ADC и USB.

http://s6.uploads.ru/t/A9PoW.png

Нажимаем на кнопку Finish и проект будет создан и откроется в IDE.
По умолчанию будет подобный код.

Код:
program MyProject

' Declarations section 

main:
'   Main program 
end.

Заменяем его на этот.

Код:
program HID_TermoADC

const tV_25  as float = 1.34   ' Напряжение (в вольтах) на датчике при температуре 25 °C.
const tSlope as float = 0.0043 ' Изменение напряжения (в вольтах) при изменении температуры на градус.
const Vref   as float = 3.3    ' Образцовое напряжение АЦП (в вольтах).

dim readbuff as byte[2]
dim writebuff as byte[2]
dim Result as integer
dim temp as float

sub procedure USB1Interrupt() iv IVT_INT_USB_LP_CAN_RX0 ics ICS_AUTO
  USB_Interrupt_Proc()               ' Обработка прерывания от USB.
end sub

main:
  ADC1_Init()
  ADC1_CR2.TSVREFE=1                 ' Включаем датчик температуры.
  HID_Enable(@readbuff,@writebuff)
  while TRUE
    Result = ADC1_Get_Sample(16)     ' Читаем температуру с 16 канала первого АПЦ.
    temp =  Result
    temp = (temp/4096)*Vref          ' Напряжение в вольтах на датчике.
    temp = (tV_25-temp)/tSlope + 25  ' Температура в градусах.
    temp = temp * 16                 ' Приводим данные к формату DS18B20.
    Result = temp
    while(HID_Write(@Result, 2) = 0) ' Передача данных в компьютер.
    wend
    delay_ms(1000)                   ' Ждем секунду.
  wend
end.

Также нужно отредактировать файл USBdsc.mbas. В его начале есть строки, в которых заданны параметры USB устройства, такие как  PID и VID, количество байт INPUT и OUTPUT конечных точек, интервал опроса и т. д.

Код:
const USB_VENDOR_ID as word = 0x1234
const USB_PRODUCT_ID as word = 0x0001
const USB_SELF_POWER as char = 0x80            ' Self powered 0xC0,  0x80 bus powered
const USB_MAX_POWER as char = 50               ' Bus power required in units of 2 mA
const HID_INPUT_REPORT_BYTES as char = 64
const HID_OUTPUT_REPORT_BYTES as char = 64
const EP_IN_INTERVAL as char = 1
const EP_OUT_INTERVAL as char = 1

Их нужно отредактировать.

Код:
const USB_VENDOR_ID as word = 0xAAAA
const USB_PRODUCT_ID as word = 0xEF04
const USB_SELF_POWER as char = 0x80            ' Self powered 0xC0,  0x80 bus powered
const USB_MAX_POWER as char = 50               ' Bus power required in units of 2 mA
const HID_INPUT_REPORT_BYTES as char = 2
const HID_OUTPUT_REPORT_BYTES as char = 2
const EP_IN_INTERVAL as char = 100
const EP_OUT_INTERVAL as char = 100

Также необходимо настроить тактирование МК (меню Project пункт "Edit Project").

http://s7.uploads.ru/t/FfPbZ.png

http://s9.uploads.ru/t/KLxGy.png

В STM32CubeMX это делать проще, т. к. визуально видно что с чем соединено и как изменяемые параметры влияют на конфигурацию тактирования. Но если посмотреть на эти скриншоты и на скриншот в первом сообщении где показана вкладка "Clock configuration", то можно понять что для чего нужно.

Теперь компилируем программу и получаем прошивку. Но как писал выше, из АЦП неправильно считывается напряжение на датчике...
Файлы. http://pure-basic.narod.ru/forum_files/ … rmoADC.zip

0

3

Пётр написал(а):

Аналогичная программа на mikroBasic. Скажу сразу, код нормально не заработал. С АЦП читается не то что должно (не то что в программе на Си), но все же решил его выложить. Может у кого будут идеи почему работает не так как должно.

Решил разобраться почему в mikroBasic неправильно считывается температура с датчика.
В первую очередь проанализировал состояние регистров АЦП (их 20 штук,  и они 32-ух битные :D) чтобы понять что не так.

Скриншоты регистров

Слева регистры в Си-программе, а справа в mikroBasic.
http://s0.uploads.ru/pTf1y.png  http://s1.uploads.ru/PksYe.png

Разница не очень большая. Регистр SR статусный и на него в данном случае можно не обращать внимания. В регистре CR2 отличается 20 бит, отвечающий за триггер запуска преобразования АПЦ и в данном случае, так же не влияет на результат. Регистр SMPR1 задает количество циклов преобразования. Регистр DR это регистр данных, куда помещается измеренное значение. На скриншотах видно что mikroBasic завышает показания примерно на 150 и их изменение не очень похоже на нагрев или охлаждение кристалла.
Так как в регистрах АЦП не нашел ничего такого что могло бы привести к искажению результата преобразования, предположил что возможно дело в инициализации АЦП, или в методе чтения с него. Начал проверять с инициализации. Заменил функцию ADC1_Init() на этот код, найденный в сети.

Код:
  RCC_APB2ENR.ADC1EN=1 ' Подаем такты на АЦП
  ADC1_CR2.CAL = 1     ' Запуск калибровки АЦП
  delay_us(400)        ' Ожидаем окончания калибровки
  ADC1_CR2.TSVREFE=1   ' Подаем питание на темп. сенсор и датчик напр.
  ADC1_CR2.EXTSEL0=1   ' Запуск преобразования по установке бита swstart
  ADC1_CR2.EXTTRIG=1   ' Включаем запуск от внешнего события (у нас это свтарт)
  ADC1_SMPR1 = 1310720
  ADC1_CR2.ADON=1      ' Подаем питание на АЦП

Показания стали больше похожими на то что должно быть (в регистре DR было значение примерно 1770), но все равно не то, и измеренная температура была примерно на 10 градусов занижена. В пошаловой отладке заметил что после включения АЦП в регистр данных записывалось число 70 и если его вычесть из результата измерения, то получалось именно то что нужно. :)  Возможно это калибровочное значение.
Код.

Код:
program HID_TermoADC

const tV_25  as float = 1.34   ' Напряжение (в вольтах) на датчике при температуре 25 °C.
const tSlope as float = 0.0043 ' Изменение напряжения (в вольтах) при изменении температуры на градус.
const Vref   as float = 3.3    ' Образцовое напряжение АЦП (в вольтах).

dim readbuff as byte[2]
dim writebuff as byte[2]
dim Result as integer
dim temp as float
dim correct as integer

sub procedure USB1Interrupt() iv IVT_INT_USB_LP_CAN_RX0 ics ICS_AUTO
  USB_Interrupt_Proc() ' Обработка прерывания от USB.
end sub

main:
'  ADC1_Init()
'  ADC1_CR2.TSVREFE=1  ' Включаем датчик температуры.

  RCC_APB2ENR.ADC1EN=1 ' Подаем такты на АЦП
  ADC1_CR2.CAL = 1     ' Запуск калибровки АЦП
  delay_us(400)        ' Ожидаем окончания калибровки
  ADC1_CR2.TSVREFE=1   ' Подаем питание на темп. сенсор и датчик напр.
  ADC1_CR2.EXTSEL0=1   ' Запуск преобразования по установке бита swstart
  ADC1_CR2.EXTTRIG=1   ' Включаем запуск от внешнего события (у нас это свтарт)
  ADC1_SMPR1 = 1310720
  ADC1_CR2.ADON=1      ' Подаем питание на АЦП
  delay_us(400)
  correct = ADC1_DR
  
  HID_Enable(@readbuff,@writebuff)
  while TRUE
  
    Result = ADC1_Get_Sample(16)     ' Читаем температуру с 16 канала первого АПЦ.
               
    temp =  Result - correct
    temp = (temp/4096)*Vref          ' Напряжение в вольтах на датчике.
    temp = (tV_25-temp)/tSlope + 25  ' Температура в градусах.
    temp = temp * 16                 ' Приводим данные к формату DS18B20.
    Result = temp
    
    while(HID_Write(@Result, 2) = 0) ' Передача данных в компьютер.
    wend
    
    delay_ms(1000)                   ' Ждем секунду.
  wend
end.

Проект. http://pure-basic.narod.ru/forum_files/ … oADC_2.zip

0

4

Что-то не получается, несколько раз делал точно по вашей инструкции, но в результате при подключении надпись "Нет связи с термометром" изменяется на "Термометр подключен" но вместо температуры пишет "OFF".
+ ещё после прошивки программатор перестает подключатся к плате с ошибкой "Can not connect to target!
Please select "Connect Under Reset" mode from Target->Settings menu and try again.
If you're trying to connect to a low frequency application , please select a lower SWD Frequency mode from Target->Settings menu.
" помогает перестановка джамперов на плате в противоположное положение.
Пробовал прошивать вашей прошивкой из архива, работает все отлично и программатор видит после прошивки.
Плата :
http://cs7050.vk.me/c540106/v540106167/40639/QAtK9_MPK1Y.jpg

0

5

То ли вы какой-то нюанс упустили, то ли программа emblocks или cubemx битая (хотя скачивал по вашим ссылкам из оф. источников)

0

6

Похоже что дело в кубе (STM32CubeMX). Я использовал версию 4.14.0. В версии 4.15.0 зачем-то переименовали переменную-идентификатор USB устройства с hUsbDevice_0 в hUsbDeviceFS. В итоге передача по USB не работала.
Проект для версии 4.15.0. http://pure-basic.narod.ru/forum_files/ … 4.15.0.zip

+2

7

Изменил в main.c hUsbDevice_0 на hUsbDeviceFS, температура начала отображается, но проблема с программатором осталась хотя с вашей прошивкой (первой) все отлично, буду копать дальше, попробую поставить cubeMX 4.14.
Спасибо за помощь!

0

8

В кубе нужно включить поддержку отладки.

http://s017.radikal.ru/i437/1606/69/82125540ce7e.png

В версии 4.14.0 отладка работала без этого, а в 4.15.0 нужно обязательно выбирать тип отладки.

+2

9

сейчас попробуем

0

10

Все работает! Огромное вам спасибо!  :cool:

+1

11

хотя размер прошивки в 41,3 Кб немного напрягает :stupor: , ето нормально для данной программы ?

0

12

Это размер HEX файла? Он текстовый и имеет размер больше чем реальный объем прошивки.
Например в архиве выше размер HEX файла (папка "HID_TermoADC\bin\Release") равен 33549 байт, а реальный размер прошивки (судя по программе ST-LINK Utility) составляет 11900 байт.

0

13

а, ну тогда ладно.
ставил галочку напротив оптимизации размера, но всеровно больше чем у вас получилось (41,3Кб против ваших 32,7Кб)

0

14

Есть еще "Use Link Time Optimization".

http://s018.radikal.ru/i528/1606/82/8f8eb2d08362.png

0

15

Спасибо!  :)
Жду продолжение ваших топиков (уроков, советов по поводу STM)

0


Вы здесь » Программирование ATMEL в BASCOM. » Не пора ли нам попробовать ARM? » (Пример работы с АЦП и USB) Чтение температуры со встроенного датчика