本帖最后由 Ketose 于 2016-1-23 09:18 编辑
测量数据的使用0.96寸的12864显示输出(完结)
1、OLED介绍
0.96’ OLED 显示模块, 分辨率为 128*64,采用SSD1306 驱动 IC,该芯片内部集成 DCDC 升压,仅需 3.3V 供电,即可正常工作。实际上就是由一个SSD1306控制器和一个128X64的有机发光二极管点阵组成。具体更详细的资料大家可以到网上查,我这里不做详细介绍了。
2、模块的接口原理图
在K22F上,使用SPI1来驱动。
3、整个系统原理图
4、OLED驱动部分代码:
/**
****************************************************************************************
*
* [url=home.php?mod=space&uid=288409]@file[/url] lcd_12864.c
*
* [url=home.php?mod=space&uid=247401]@brief[/url] lcd_12864 driver.
*
* Copyright (C) TChip 2014
*
* $Rev: 1.0 $
*
****************************************************************************************
*/
/**
****************************************************************************************
* @addtogroup SPI
* @{
****************************************************************************************
*/
/*
* INCLUDE FILES
****************************************************************************************
*/
#include "fsl_dspi_master_driver.h"
#include "fsl_spi_master_driver.h"
#include "fsl_gpio_hal.h"
#include "fsl_port_hal.h"
#include "fsl_debug_console.h"
#include "delay.h"
#include "oled.h"
#include "oledfont.h"
/*
* MARCO VARIABLE DECLARATION
****************************************************************************************
*/
#define TRANSFER_SIZE (1) /*! Transfer size */
#define TRANSFER_BAUDRATE (1000000U) /*! Transfer baudrate - 500k */
#define MASTER_TRANSFER_TIMEOUT (5000U) /*! Transfer timeout of master - 5s */
/*
* LOCAL VARIABLE DECLARATION
****************************************************************************************
*/
//check spi status
volatile uint8_t oled_rx_flag = 0;
volatile uint8_t oled_tx_flag = 0;
//uint8_t i;
uint8_t buffer[32];
//Init the OLED
//static uint8_t Init_buffer[] =
//{
// 0xAE ,//--turn off oled panel
// 0x00 ,//---set low column address
// 0x10 ,//---set high column address
// 0x40 ,//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
// 0x81 ,//--set contrast control register
// 0xCF , // Set SEG Output Current Brightness
// 0xA1 ,//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
// 0xC8 ,//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
// 0xA6 ,//--set normal display
// 0xA8 ,//--set multiplex ratio(1 to 64)
// 0x3f ,//--1/64 duty
// 0xD3 ,//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
// 0x00 ,//-not offset
// 0xd5 ,//--set display clock divide ratio/oscillator frequency
// 0x80 ,//--set divide ratio, Set Clock as 100 Frames/Sec
// 0xD9 ,//--set pre-charge period
// 0xF1 ,//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
// 0xDA ,//--set com pins hardware configuration
// 0x12 ,
// 0xDB ,//--set vcomh
// 0x40 ,//Set VCOM Deselect Level
// 0x20 ,//-Set Page Addressing Mode (0x00/0x01/0x02)
// 0x02 ,//
// 0x8D ,//--set Charge Pump enable/disable
// 0x14 ,//--set(0x10) disable
// 0xA4 ,// Disable Entire Display On (0xa4/0xa5)
// 0xA6 ,// Disable Inverse Display On (0xa6/a7)
// 0xAF ,//--turn on oled panel
//
// 0xAF , /*display ON*/
//};
/*
* GLOBAL VARIABLE DECLARATION
****************************************************************************************
*/
#if (NXP_OLED)
//void DelayUs(uint32_t us)
//{
// for(int i=us*30;i>0;i--)
// __NOP();
//}
//void DelayMs(uint32_t ms)
//{
// for(int i=ms;i>0;i--)
// DelayUs(1000);
//}
/**
****************************************************************************************
* [url=home.php?mod=space&uid=247401]@brief[/url] SPI RX CALLBACK FUNCTION.
* @description
*
****************************************************************************************
*/
void oled_read_done(void)
{
oled_rx_flag = 0;
}
/**
****************************************************************************************
* [url=home.php?mod=space&uid=247401]@brief[/url] SPI TX CALLBACK FUNCTION.
* @description
*
****************************************************************************************
*/
void oled_write_done(void)
{
oled_tx_flag = 0;
}
/**
****************************************************************************************
* @brief Configure the SPI GPIO and set RS 、 RST GPIO output,Init them.
* @description
*
****************************************************************************************
*/
void oled_io_config(void)
{
//Init Gpio with a callback,it's necessary
//set the LCD_RS_PIN an output
PORT_HAL_SetMuxMode(PORTB,OLED_DC_PIN,kPortMuxAsGpio);
GPIO_HAL_SetPinDir(OLED_DC,OLED_DC_PIN,kGpioDigitalOutput);
GPIO_HAL_ClearPinOutput(OLED_DC,OLED_DC_PIN);
//set the LCD_RST_PIN an output
//prevent it reset the lcd
PORT_HAL_SetMuxMode(PORTC,OLED_RST_PIN,kPortMuxAsGpio);
GPIO_HAL_SetPinDir(OLED_RST,OLED_RST_PIN,kGpioDigitalOutput);
GPIO_HAL_SetPinOutput(OLED_RST,OLED_RST_PIN);
}
void OLED_Set_Pos(unsigned char x, unsigned char y)
{
OLED_WR_Byte(0xb0+y,OLED_CMD);
OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
OLED_WR_Byte((x&0x0f)|0x01,OLED_CMD);
}
//开启OLED显示
void OLED_Display_On(void)
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X14,OLED_CMD); //DCDC ON
OLED_WR_Byte(0XAF,OLED_CMD); //DISPLAY ON
}
//关闭OLED显示
void OLED_Display_Off(void)
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X10,OLED_CMD); //DCDC OFF
OLED_WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF
}
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
void OLED_Clear(void)
{
uint8_t i,n;
for(i=0; i<8; i++)
{
OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (0x00,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0; n<128; n++)
OLED_WR_Byte(0,OLED_DATA);
} //更新显示
}
void OLED_WR_Byte(uint8_t dat,uint8_t cmd)
{
dspi_status_t dspiResult;
buffer[0] = dat;
if(cmd)
OLED_DC_Set();
else
OLED_DC_Clr();
OLED_CS_Clr();
//spi_write(QN_SPI1, buffer, 1, oled_write_done);
dspiResult = DSPI_DRV_MasterTransferBlocking(SPI1_IDX,
NULL,
buffer,
NULL,
1,
MASTER_TRANSFER_TIMEOUT);
if(kStatus_DSPI_Success != dspiResult)
while(1);
oled_write_done();
DelayUs(100);
OLED_CS_Set();
OLED_DC_Set();
}
//void OLED_WR_Byte(uint8_t dat,uint8_t cmd)
//{
// //uint8_t i;
// uint8_t buffer[1];
// buffer[0] = dat;
// if(cmd)
// OLED_DC_Set();
// else
// OLED_DC_Clr();
// OLED_CS_Clr();
// spi_write(QN_SPI1, buffer, 1, lcd_write_done);
// delay(100);
//
// OLED_CS_Set();
// OLED_DC_Set();
//}
void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr)
{
unsigned char c=0,i=0;
c=chr-' ';//得到偏移后的值
if(x>Max_Column-1) {
x=0;
y=y+2;
}
if(SIZE ==16)
{
OLED_Set_Pos(x,y);
for(i=0; i<8; i++)
OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
OLED_Set_Pos(x,y+1);
for(i=0; i<8; i++)
OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
}
else {
OLED_Set_Pos(x,y+1);
for(i=0; i<6; i++)
OLED_WR_Byte(F6x8[c][i],OLED_DATA);
}
}
//m^n函数
uint32_t oled_pow(uint8_t m,uint8_t n)
{
uint32_t result=1;
while(n--)result*=m;
return result;
}
//显示2个数字
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//mode:模式 0,填充模式;1,叠加模式
//num:数值(0~4294967295);
void OLED_ShowNum(uint8_t x,uint8_t y,uint32_t num,uint8_t len,uint8_t size)
{
uint8_t t,temp;
uint8_t enshow=0;
for(t=0; t<len; t++)
{
temp=(num/oled_pow(10,len-t-1))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
OLED_ShowChar(x+(size/2)*t,y,' ');
continue;
} else enshow=1;
}
OLED_ShowChar(x+(size/2)*t,y,temp+'0');
}
}
//显示一个字符号串
void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr)
{
unsigned char j=0;
while (chr[j]!='\0')
{ OLED_ShowChar(x,y,chr[j]);
x+=8;
if(x>120) {
x=0;
y+=2;
}
j++;
}
}
//显示汉字
void OLED_ShowCHinese(uint8_t x,uint8_t y,uint8_t no)
{
uint8_t t,adder=0;
OLED_Set_Pos(x,y);
for(t=0; t<16; t++)
{
OLED_WR_Byte(Hzk[2*no][t],OLED_DATA);
adder+=1;
}
OLED_Set_Pos(x,y+1);
for(t=0; t<16; t++)
{
OLED_WR_Byte(Hzk[2*no+1][t],OLED_DATA);
adder+=1;
}
}
/***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])
{
unsigned int j=0;
unsigned char x,y;
if(y1%8==0) y=y1/8;
else y=y1/8+1;
for(y=y0; y<y1; y++)
{
OLED_Set_Pos(x0,y);
for(x=x0; x<x1; x++)
{
OLED_WR_Byte(BMP[j++],OLED_DATA);
}
}
}
void SPI_Init()
{
static uint32_t calculatedBaudRate;
static dspi_master_state_t masterState;
static dspi_device_t masterDevice;
static dspi_master_user_config_t masterUserConfig = {
.isChipSelectContinuous = false,
.isSckContinuous = false,
.pcsPolarity = kDspiPcs_ActiveLow,
.whichCtar = kDspiCtar0,
.whichPcs = kDspiPcs0
};
dspi_status_t dspiResult;
// Setup the configuration.
masterDevice.dataBusConfig.bitsPerFrame = 8;
masterDevice.dataBusConfig.clkPhase = kDspiClockPhase_FirstEdge;
masterDevice.dataBusConfig.clkPolarity = kDspiClockPolarity_ActiveHigh;
masterDevice.dataBusConfig.direction = kDspiMsbFirst;
// Initialize master driver.
dspiResult = DSPI_DRV_MasterInit(SPI1_IDX,
&masterState,
&masterUserConfig);
while(dspiResult != kStatus_DSPI_Success);
// Configure baudrate.
masterDevice.bitsPerSec = 32;
dspiResult = DSPI_DRV_MasterConfigureBus(SPI1_IDX,
&masterDevice,
&calculatedBaudRate);
while(dspiResult != kStatus_DSPI_Success);
}
//初始化SSD1306
void OLED_Init(void)
{
oled_io_config();
SPI_Init();
OLED_RST_Set();
DelayMs(10);
OLED_RST_Clr();
DelayMs(10);
OLED_RST_Set();
OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
OLED_WR_Byte(0x40,OLED_CMD);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register
OLED_WR_Byte(0xCF,OLED_CMD); // Set SEG Output Current Brightness
OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display
OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty
OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
OLED_WR_Byte(0x00,OLED_CMD);//-not offset
OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
OLED_WR_Byte(0x12,OLED_CMD);
OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh
OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level
OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
OLED_WR_Byte(0x02,OLED_CMD);//
OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)
OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
OLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/
OLED_Clear();
OLED_Set_Pos(0,0);
}
#endif
///end
5、主程序代码
/*
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* [File Name] main.c
* [Platform] FRDM-K22F
* [Project] K22F_PM25
* [Version] 1.00
* [Author] Goth
* [Date] 01/19/2016
* [Language] 'C'
* [History] 1.00 - Original Release
*
*/
//-----------------------------------------------------------------------
// Standard C/C++ Includes
//-----------------------------------------------------------------------
#include <stdio.h>
#include <math.h>
//-----------------------------------------------------------------------
// KSDK Includes
//-----------------------------------------------------------------------
#include "main.h"
//-----------------------------------------------------------------------
// Application Includes
//-----------------------------------------------------------------------
#include "oled.h"
#include "dht11.h"
#include "gp2y.h"
#include "ch2o.h"
#include "delay.h"
//-----------------------------------------------------------------------
// Function Prototypes
//-----------------------------------------------------------------------
void ReadCH2O(void);
void ReadDHT11(void);
void ReadGP2Y(void);
//-----------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// Typedefs
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// Global Variables
//-----------------------------------------------------------------------
extern char **[];
//-----------------------------------------------------------------------
// Macros
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
// Main Function
//-----------------------------------------------------------------------
int main(void)
{
// Configure board specific pin muxing
hardware_init();
OSA_Init();
// Initialize UART terminal
dbg_uart_init();
DelayInit();
DHT11_Init();
CH2O_Init();
GP2Y_init();
OLED_Init();
OLED_Clear();
PRINTF("\r\nRunning the K22F_PM25 project.\r\n");
//Show **
OLED_DrawBMP(0,0,128,8,(unsigned char*)**);
DelayMs(1000);
OLED_Clear();
for (;;) // Forever loop
{
ReadCH2O();
ReadDHT11();
ReadGP2Y();
DelayUs(1000);
}
}
void ReadCH2O(void)
{
uint8_t receiveBuffer[32];
uint8_t rx;
rx = 0x00;
for(int i=0;i<9;i++)
receiveBuffer[i] = 0;
// Call received API
UART_DRV_ReceiveData(UART2_IDX, &rx, 1u);
// Wait until we receive a character
while (kStatus_UART_RxBusy == UART_DRV_GetReceiveStatus(UART2_IDX, NULL));
if(rx == 0xFF)
{
receiveBuffer[0] = rx;
for(int i=1;i<9;i++)
{
// Call received API
UART_DRV_ReceiveData(UART2_IDX, &rx, 1u);
// Wait until we receive a character
while (kStatus_UART_RxBusy == UART_DRV_GetReceiveStatus(UART2_IDX, NULL));
receiveBuffer[i] = rx;
}
}
/*国家标准室内0.08mg/m3 = 833 * 0.08 = 66.64 ppb。*/
int pm25Value = receiveBuffer[4]*256 + receiveBuffer[5];
float result = pm25Value / 66.64 * 0.08;
/*
int v1 = (int)result;
int v2 = (int)((result - v1)*1000);
PRINTF("CH2O: %d.%03d(mg/m3)\r\n",v1,v2);
*/
sprintf((char*)receiveBuffer,":%1.3f mg/",result);
OLED_ShowCHinese(0,0,4);//显示汉字甲
OLED_ShowCHinese(16,0,5);//显示汉字醛
OLED_ShowString(32,0,receiveBuffer);
OLED_ShowCHinese(112,0,10);//显示m³
}
void ReadDHT11(void)
{
uint8_t showBuffer[32];
uint8_t temp;
uint8_t humi;
DHT11_Read_Data(&temp,&humi);
sprintf((char*)showBuffer,":%3d",temp);
OLED_ShowCHinese(0,2,6);//显示汉字温
OLED_ShowCHinese(16,2,8);//显示汉字度
OLED_ShowString(32,2,showBuffer);
OLED_ShowCHinese(64,2,9);//显示℃
sprintf((char*)showBuffer,":%3d",humi);
OLED_ShowCHinese(0,4,7);//显示汉字温
OLED_ShowCHinese(16,4,8);//显示汉字度
OLED_ShowString(32,4,showBuffer);
OLED_ShowCHinese(64,4,11);//显示%
}
void ReadGP2Y(void)
{
uint8_t showBuffer[32];
int new_pm25 = 0;
static int prev_pm25 = 0;
int last_pm25 = 0;
GP2Y_ON;
DelayUs(280);
float adValue = GP2Y_Read();
DelayUs(40);
GP2Y_OFF;
DelayUs(9680);
/*无尘测得电压值为0.6,手册上每0.1mg/m3 电压增加0.5V
*使用excel记算得出公式:y = 0.2x-0.12 */
new_pm25 = (0.2f*adValue-0.12f)*1000; //电压-灰尘转换
/*一阶滤波*/
last_pm25 = 0.2*new_pm25+0.8*prev_pm25;
prev_pm25 = new_pm25;
sprintf((char*)showBuffer,"PM25:%3d ug/",last_pm25);
OLED_ShowString(0,6,showBuffer);
OLED_ShowCHinese(112,6,10);//显示m³
}
////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////
6、效果演示
|