前面我們學習了STM32智能家居系統中的溫濕度檢測及控制系統。這一期我們學習光照檢測控制系統。
7.1 項目的介紹
如圖1所示。整體項目采用光敏傳感器采取環境的光照強度,當光照強度的值高于某一設定值時(光照強度的數值與外界環境的亮度成反比,外界越亮,值越小),電機逆時針轉動,模仿打開遮陽簾,LED燈點亮;當光照強度的值低于某一設定值時,電機順時針轉動,模仿關閉遮陽簾。
圖1 項目整體圖
7.2 光敏傳感器
如圖2所示,光敏傳感器通過PB0引腳接入STM32。
囷2 光敏傳感器與STM32連接原理圖
圖中,LS1是光敏二極管,R1為其提供反向電壓,當環境光線變化時,LS1兩端的電壓也會随之改變,從而通過ADC1_IN6通道,讀取LIGHT_SENSOR(PB0)上面的電壓,即可得到環境光線的強弱。光線越強,電壓越低,光線越暗,電壓越高。
7.3 采用ADC方式采集數據
ADC是将采集的模拟量轉化成數字量,對于STM32而言,它需要一個輸入的基準電壓,用于和待測的模拟電壓做對比。
STM32f103系列最多有3個ADC,精度為12位,每個ADC最多有16個外部通道。其中ADC1和ADC2都有16個外部通道,ADC3一般有8個外部通道,各通道的A/D轉換可以單次、連續、掃描或間斷執行,ADC轉換的結果可以左對齊或右對齊儲存在16位數據寄存器中。ADC的輸入時鐘不得超過14MHz,其時鐘頻率由PCLK2分頻産生。
STM32将ADC的轉換分為2個通道組:規則通道組和注入通道組。規則通道相當于正常運行的程序,而注入通道呢,就相當于中斷。在你程序正常執行的時候,中斷是可以打斷你的執行的。同這個類似,注入通道的轉換可以打斷規則通道的轉換,在注入通道被轉換完成之後,規則通道才得以繼續轉換。
圖3是STM32的ADC通道與GPIO對應表:
圖3 STM32的ADC通道與GPIO對應表
利用ADC完成數據采集需要采取以下步驟:
圖4 ADC采集邏輯圖
代碼如下:
adc.h
#ifndef __ADC_H
#define __ADC_H
#include "sys.h"
void Adc_Init(void);
u16 Get_Adc(u8 ch);
u16 Get_Adc_Average(u8 ch,u8 times);
#endif
adc.h是ADC完成數據采集代碼的頭文件,在頭文件中,定義了三個函數,一個是void Adc_Init(void),進行Adc通道的初始化,主要完成Adc1通道的引腳的定義(PB0)和ADC模式的定義;第二個函數是u16 Get_Adc(u8 ch),這個函數完成對Adc通道數據的采集;第三函數是u16 Get_Adc_Average(u8 ch,u8 times),完成對該通道多次采集的數據平均值。
adc.c
#include "adc.h"
#include "delay.h"
#include "usart.h"
//初始化ADC
//這裡我們僅以規則通道為例
//我們默認将開啟通道0~3
void Adc_Init(void)
{
ADC_InitTypeDef ADC_InitStructure; //聲明ADC結構體
GPIO_InitTypeDef GPIO_InitStructure;//聲明GPIO結構體
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |RCC_APB2Periph_ADC1, ENABLE ); //使能ADC1通道時鐘
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //設置ADC分頻因子6 72M/6=12,ADC最大時間不能超過14M
//PA1 作為模拟通道輸入引腳
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟輸入引腳
GPIO_Init(GPIOB, &GPIO_InitStructure);
ADC_DeInit(ADC1); //複位ADC1
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在獨立模式
ADC_InitStructure.ADC_ScanConvMode = ENABLE; //模數轉換工作在單通道模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //模數轉換工作在單次轉換模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //轉換由軟件而不是外部觸發啟動
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC數據右對齊
ADC_InitStructure.ADC_NbrOfChannel = 1; //順序進行規則轉換的ADC通道的數目
ADC_Init(ADC1, &ADC_InitStructure); //根據ADC_InitStruct中指定的參數初始化外設ADCx的寄存器
ADC_Cmd(ADC1, ENABLE); //使能指定的ADC1
ADC_ResetCalibration(ADC1); //使能複位校準
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
}
//獲得ADC值
//ch:通道值 0~3
u16 Get_Adc(u8 ch)
{
//設置指定ADC的規則組通道,一個序列,采樣時間
ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道,采樣時間為239.5周期
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的軟件轉換啟動功能
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待轉換結束
return ADC_GetConversionValue(ADC1); //返回最近一次ADC1規則組的轉換結果
}
u16 Get_Adc_Average(u8 ch,u8 times)
{
u32 beam_value=0;
u8 t;
for(t=0;t<times;t )
{
beam_value =Get_Adc(ch);
delay_ms(5);
}
return beam_value/times;
7.4 串口通信
為了顯示光照強度的數值,我們在項目中開始設置串口進行顯示所采集的數值。
首先,我們先來了解串口通信的基本概念。
串口通信(Serial Communications)的概念非常簡單,串口按位(bit)發送和接收字節。具體如圖5所示。
圖5 串口通信示意圖
從圖5中可知, 串口是一位一位地将數據發送出去,接收時也是一位一位的進行接收,但是,在計算機當中 ,數據的處理是按字節進行并行處理的,所以要想把數據按位的進行發送和接收,就需要串行接口電路的工作。
串行接口電路就是一種可以将接收來自CPU的并行數據字符轉換為連續的串行數據流發送出去,同時可将接收的串行數據流轉換為并行的數據字符供給CPU的器件的接口電路。
在串口接口電路的幫助下,串口通信可以很順利地實現,那麼串口通信有哪些優點和缺點呢?
串口通信的缺點非常明顯,就是按位的串行通行比按字節(byte)的并行通信慢;但是串口通信的優點也同時非常明顯。
第一:結構簡單:串口可以使用四根線就完成通信,一根為VCC電源,一根為GND地線,另外兩根線分别為RXD和TXD,RXD完成發送數據,TXD完成接收數據。
第三:通信距離長:相對于其他的通信方式,串口通信的距離可達1200米,這個距離已經很長了。
配置串口通信需要多個參數,其中最重要的是波特率、數據位、停止位和奇偶校驗。對于兩個進行通信的端口,這些參數必須匹配。
波特率
波特率用來衡量符号傳輸的速率。具體指的是信号被調制以後在單位時間内的變化,即單位時間内載波參數變化的次數,如每秒鐘傳送240個字符,而每個字符格式包含10位(1個起始位,1個停止位,8個數據位),這時的波特率為240Bd,比特率為10位*240個/秒=2400bps。波特率和距離成反比。高波特率常常用于放置的很近的儀器間的通信。
數據位
這是衡量通信中實際數據位的參數。當計算機發送一個信息包,實際的數據往往不會是8位的,标準的值是6、7和8位。如何設置取決于你想傳送的信息。比如,标準的ASCII碼是0~127(7位)。擴展的ASCII碼是0~255(8位)。如果數據使用簡單的文本(标準 ASCII碼),那麼每個數據包使用7位數據。每個包是指一個字節,包括開始/停止位,數據位和奇偶校驗位。由于實際數據位取決于通信協議的選取,術語“包”指任何通信的情況。
停止位
停止位用于表示單個包的最後一位。典型的值為1,1.5和2位。由于數據是在傳輸線上定時的,并且每一個設備有其自己的時鐘,很可能在通信中兩台設備間出現了小小的不同步。因此停止位不僅僅是表示傳輸的結束,并且提供計算機校正時鐘同步的機會。适用于停止位的位數越多,不同時鐘同步的容忍程度越大,但是數據傳輸率同時也越慢。
奇偶校驗位
在串口通信中一種簡單的檢錯方式。有四種檢錯方式:偶、奇、高和低。當然沒有校驗位也是可以的。對于偶和奇校驗的情況,串口會設置校驗位(數據位後面的一位),用一個值确保傳輸的數據有偶個或者奇個邏輯高位。例如,如果數據是011,那麼對于偶校驗,校驗位為0,保證邏輯高的位數是偶數個。如果是奇校驗,校驗位為1,這樣就有3個邏輯高位。高位和低位不真正的檢查數據,簡單置位邏輯高或者邏輯低校驗。這樣使得接收設備能夠知道一個位的狀态,有機會判斷是否有噪聲幹擾了通信或者是否傳輸和接收數據是否不同步。
串口設置的一般步驟可以總結為如下幾個步驟:
1) 串口時鐘使能,GPIO時鐘使能;
2) 串口複位;
3) GPIO端口模式設置;
4) 串口參數初始化;
5) 開啟中斷并且初始化NVIC(如果需要開啟中斷才需要這個步驟);
6) 使能串口;
7) 編寫中斷處理函數;
相關程序以及解釋如下:
首先定義一個函數,函數命名為uart_init,函數的輸入變量為波特率bound。
在函數uart_init中是按照上面的7個步驟進行定義。
void uart_init(u32 bound){
//定義三個結構體:GPIO、串口、中斷
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//使能USART1,GPIOA時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);
//定義串口的TX和RX的GPIO
//定義USART1_TX ,使用GPIOA.9,發送數據,采用推挽輸出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //複用推挽輸出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
//定義USART1_RX,使用 GPIOA.10,接收數據,采取浮空輸入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空輸入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//搶占優先級3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子優先級3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根據指定的參數初始化VIC寄存器
//USART 初始化設置
USART_InitStructure.USART_BaudRate = bound;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字長為8位數據格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一個停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//無奇偶校驗位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無硬件數據流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收發模式
//初始化串口
USART_Init(USART1, &USART_InitStructure); //初始化串口1
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//開啟串口接受中斷
USART_Cmd(USART1, ENABLE); //使能串口1
}
定義好串口之後,就可以調用了,在需要的地方,使用uart_init(******)進行初始化,中間的****為設定的波特率。同時采取printf(*****)輸出串口的數據,在本例中,串口隻是用來輸出光敏電阻的數據,所以串口隻用來輸出數據;
以上是STM32 智能家居系統中光敏傳感器和串口的工作。歡迎共同讨論,糾錯。期待關注、點贊、轉發。粉絲朋友可直接私信索要相關資料(項目源碼)。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!