Для знакомства с АЦП сразу соберём полезный прибор: USB-термометр. Для этого нам понадобятся:
- аналоговый термодатчик LM35 от National Semiconductor (правда, это уже Texas Instruments)
- STM32VLDiscovery
- UART-USB конвертер FT232
Аналоговые термодатчики широко используются, несмотря на наличие цифровых — они дешевле и несколько проще в программировании. Благодаря наличию встроенных АЦП в STM32 всё подключение сводится просто к использованию одной из ног АЦП.
Я традиционно применяю именно LM35, в одном из серийных устройств они себя хорошо показали, да и стоимость невысока — 70 рублей за штуку. Однако, в стандартном включении они могут измерять лишь положительные температуры, а для полного диапазон производитель предлагает не слишком удобную схему со смещением нуля. Его фичи:
- напряжение питания — от 4 вольт
- точность — не хуже чем полградуса
- высокая линейность выходной характеристики на всём диапазоне
- очень удобная характеристика — выходное напряжение это просто 10мВ * температура. При 21 градусе на выходе 210мВ.
- 70 рублей в терраэлектронике
Популярен также датчик LM19, у него свои плюсы и минусы:
- пониженное напряжение питания —вплоть до 2.5В
- невысокая точность — 2.5 градуса
- такая же линейная характеристика
- отрицательный наклон характеристики, выше температура — ниже напряжение, при 20 градусах на выходе 1.632В.
- 45 рублей в терраэлектронике
А вообще, таких датчиков существует очень много, на любой вкус. Схема подключения у всех стандартна — одну ногу на землю, другую на питание, аналоговый сигнал — на третьей.
Программа чтения сигнала с помощью АЦП сразу вычисляет температуру и отправляет её в UART.
#include "stm32f10x_conf.h"
#include
void USART1_Send(char chr) {
while(!(USART1->SR & USART_SR_TC));
USART1->DR = chr;
}
void USART1_Send_String(char* str) {
int i=0;
while(str[i])
USART1_Send(str[i++]);
}
void main()
{
RCC->APB2ENR|= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN;
GPIOA->CRH &= !GPIO_CRH_CNF9;
GPIOA->CRH |= GPIO_CRH_CNF9_1 | GPIO_CRH_MODE9_0;
USART1->BRR = 0x9C4;
USART1->CR1 |= USART_CR1_TE | USART_CR1_UE;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_ADC1, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOB, &GPIO_InitStructure);
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_7Cycles5);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
char s[10];
while(1)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
sprintf(s, "%5.1f
", ADC_GetConversionValue(ADC1)/17.3);
USART1_Send_String(s);
}
}
Свежие комментарии