这是基于stm32的ADC采集oled(IIC)显示程序代码,使用的是模拟iic,有需要的看代码自行复制
adc.h
#ifndef __O2ADC_H
#define __O2ADC_H
#include "sys.h"
void Adc_Init(void);
u16 Get_Adc(u8 ch);
u16 Get_Adc_Average(u8 ch,u8 times);
#endif
adc.c
#include "o2adc.h"
#include "delay.h"
//
//初始化ADC
void Adc_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE ); //使能ADC1通道时钟
//RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
//PA1 作为模拟通道输入引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_DeInit(ADC1); //复位ADC1
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在独立模式
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数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 2; //顺序进行规则转换的ADC通道的数目
ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器
ADC_Cmd(ADC1, ENABLE); //使能指定的ADC1
ADC_ResetCalibration(ADC1); //使能复位校准
while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束
ADC_StartCalibration(ADC1); //开启AD校准
while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束
// ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的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 temp_val=0;
u8 t;
for(t=0;t<times;t++)
{
temp_val+=Get_Adc(ch);
delay_ms(5);
}
return temp_val/times;
}
oled.h
#ifndef __OLED_H
#define __OLED_H
#include "sys.h"
#include "io_i2c.h"
#define OLED0561_ADD 0x78 // OLED的I2C地址
#define COM 0x00 // OLED寄存器地址指令
#define DAT 0x40 // OLED 数据
void OLED0561_Init(void);//初始化
void OLED_DISPLAY_ON (void);//OLED屏开显示
void OLED_DISPLAY_OFF (void);//OLED屏关显示
void OLED_DISPLAY_LIT (u8 x);//OLED屏亮度设置(0~255)
void OLED_DISPLAY_CLEAR(void);//清屏操作
void OLED_DISPLAY_8x16(u8 x,u8 y,u16 w);//显示8x16的单个字符
void OLED_DISPLAY_8x16_BUFFER(u8 row, u8 col, u8 *str);//显示8x16的字符串
#endif
oled.c(模拟iic)
#include "oled0561.h"
#include "ASCII_8x16.h" //引入字体 ASCII
void OLED0561_Init (void){//OLED屏开显示初始化
OLED_DISPLAY_OFF(); //OLED关显示
OLED_DISPLAY_CLEAR(); //清空屏幕内容
OLED_DISPLAY_ON(); //OLED屏初始值设置并开显示
}
void OLED_DISPLAY_ON (void){//OLED屏初始值设置并开显示
u8 buf[28]={
0xae, //0xae:关显示,0xaf:开显示
0x00,0x10, //开始地址(双字节)
0xd5,0x80, //显示时钟频率?
0xa8,0x3f, //复用率?
0xd3,0x00, //显示偏移?
0XB0, //写入页位置(0xB0~7)
0x40, //显示开始线
0x8d,0x14, //VCC电源
0xa1, //设置段重新映射?
0xc8, //COM输出方式?
0xda,0x12, //COM输出方式?
0x81,0xff, //对比度,指令:0x81,数据:0~255(255最高)
0xd9,0xf1, //充电周期?
0xdb,0x30, //VCC电压输出
0x20,0x00, //水平寻址设置
0xa4, //0xa4:正常显示,0xa5:整体点亮
0xa6, //0xa6:正常显示,0xa7:反色显示
0xaf //0xae:关显示,0xaf:开显示
}; //
I2C_SAND_BUFFER(OLED0561_ADD,COM,buf,28);
}
void OLED_DISPLAY_OFF (void){//OLED屏关显示
u8 buf[3]={
0xae,//0xae:关显示,0xaf:开显示
0x8d,0x10,//VCC电源
}; //
I2C_SAND_BUFFER(OLED0561_ADD,COM,buf,3);
}
void OLED_DISPLAY_LIT (u8 x){//OLED屏亮度设置(0~255)
I2C_SAND_BYTE(OLED0561_ADD,COM,0x81);
I2C_SAND_BYTE(OLED0561_ADD,COM,x);//亮度值
}
void OLED_DISPLAY_CLEAR(void){//清屏操作
u8 j,t;
for(t=0xB0;t<0xB8;t++){ //设置起始页地址为0xB0
I2C_SAND_BYTE(OLED0561_ADD,COM,t); //页地址(从0xB0到0xB7)
I2C_SAND_BYTE(OLED0561_ADD,COM,0x10); //起始列地址的高4位
I2C_SAND_BYTE(OLED0561_ADD,COM,0x00); //起始列地址的低4位
for(j=0;j<132;j++){ //整页内容填充
I2C_SAND_BYTE(OLED0561_ADD,DAT,0x00);
}
}
}
//显示英文与数字8*16的ASCII码
//取模大小为16*16,取模方式为“从左到右从上到下”“纵向8点下高位”
void OLED_DISPLAY_8x16(u8 x, //显示汉字的页坐标(从0到7)(此处不可修改)
u8 y, //显示汉字的列坐标(从0到63)
u16 w){ //要显示汉字的编号
u8 j,t,c=0;
y=y+2; //因OLED屏的内置驱动芯片是从0x02列作为屏上最左一列,所以要加上偏移量
for(t=0;t<2;t++){
I2C_SAND_BYTE(OLED0561_ADD,COM,0xb0+x); //页地址(从0xB0到0xB7)
I2C_SAND_BYTE(OLED0561_ADD,COM,y/16+0x10); //起始列地址的高4位
I2C_SAND_BYTE(OLED0561_ADD,COM,y%16); //起始列地址的低4位
for(j=0;j<8;j++){ //整页内容填充
I2C_SAND_BYTE(OLED0561_ADD,DAT,ASCII_8x16[(w*16)+c-512]);//为了和ASII表对应要减512
c++;}x++; //页地址加1
}
}
//向LCM发送一个字符串,长度64字符之内。
//应用:OLED_DISPLAY_8_16_BUFFER(0," DoYoung Studio");
void OLED_DISPLAY_8x16_BUFFER(u8 row,u8 col, u8 *str){
//u8 r=0;
while(*str != '\0'){
OLED_DISPLAY_8x16(row,col*8,*str++);
col++;
}
}
/**
* @brief OLED_SetPos,设置光标
* @param x,光标x位置
* y,光标y位置
* @retval 无
*/
void OLED_SetPos(unsigned char x, unsigned char y) //设置起始点坐标
{
I2C_SAND_BYTE( OLED0561_ADD, COM, (0xb0+y));
I2C_SAND_BYTE( OLED0561_ADD, COM, ((x&0xf0)>>4)|0x10);
I2C_SAND_BYTE( OLED0561_ADD, COM, (x&0x0f)|0x01);
}
模拟iic.h
#ifndef __IO_I2C_H
#define __IO_I2C_H
#include "sys.h"
//模拟I2C总线驱动程序//
//I2C总线速度设置
#define VL2_SPEED 2 //取值1~255,值越小速度越快(稳定性越差),默认值为2
//IO方向设置
#define VL2_SDA_IN() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(unsigned int)8<<28;}
#define VL2_SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(unsigned int)3<<28;}
//IO操作函数
#define VL2_IIC_SCL PBout(6) //SCL
#define VL2_IIC_SDA PBout(7) //SDA
#define VL2_READ_SDA PBin(7) //输入SDA
//状态
#define STATUS_OK 0x00
#define STATUS_FAIL 0x01
//IIC操作函数
void I2C_Configuration(void);//初始化IIC的IO口
u8 I2C_SAND_BYTE(u8 address,u8 index,u8 data); //IIC写一个8位数据
u8 I2C_SAND_BUFFER(u8 address, u8 index,u8 *pdata,u16 count);//IIC连续写
u8 I2C_READ_BYTE(u8 address,u8 index,u8 *pdata); //IIC读一个8位数据
u8 I2C_READ_BUFFER(u8 address,u8 index,u8 *pdata,u16 count); //IIC连续读
#endif
模拟iic.c
这段代码其实有些臃肿,可以进行优化一下
//模拟I2C总线驱动程序//
#include "delay.h"
#include "io_i2c.h"
//I2C初始化
void I2C_Configuration(void){
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); //使能GPIOB时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50Mhz速度
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7);//PA7,PA6 输出高
}
//产生IIC起始信号
void VL2_IIC_Start(void)
{
VL2_SDA_OUT();//sda线输出
VL2_IIC_SDA=1;
VL2_IIC_SCL=1;
delay_us(VL2_SPEED*2);
VL2_IIC_SDA=0;//START:when CLK is high,DATA change form high to low
delay_us(VL2_SPEED*2);
VL2_IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void VL2_IIC_Stop(void)
{
VL2_SDA_OUT();//sda线输出
VL2_IIC_SCL=0;
VL2_IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
delay_us(VL2_SPEED*2);
VL2_IIC_SCL=1;
VL2_IIC_SDA=1;//发送I2C总线结束信号
delay_us(VL2_SPEED*2);
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 VL2_IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
VL2_SDA_IN(); //SDA设置为输入
VL2_IIC_SDA=1;delay_us(1);
VL2_IIC_SCL=1;delay_us(1);
while(VL2_READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
VL2_IIC_Stop();
return 1;
}
}
VL2_IIC_SCL=0;//时钟输出0
return 0;
}
//产生ACK应答
void VL2_IIC_Ack(void)
{
VL2_IIC_SCL=0;
VL2_SDA_OUT();
VL2_IIC_SDA=0;
delay_us(VL2_SPEED);
VL2_IIC_SCL=1;
delay_us(VL2_SPEED);
VL2_IIC_SCL=0;
}
//不产生ACK应答
void VL2_IIC_NAck(void)
{
VL2_IIC_SCL=0;
VL2_SDA_OUT();
VL2_IIC_SDA=1;
delay_us(VL2_SPEED);
VL2_IIC_SCL=1;
delay_us(VL2_SPEED);
VL2_IIC_SCL=0;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void VL2_IIC_Send_Byte(u8 txd)
{
u8 t;
VL2_SDA_OUT();
VL2_IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
if((txd&0x80)>>7)
VL2_IIC_SDA=1;
else
VL2_IIC_SDA=0;
txd<<=1;
delay_us(VL2_SPEED);
VL2_IIC_SCL=1;
delay_us(VL2_SPEED);
VL2_IIC_SCL=0;
delay_us(VL2_SPEED);
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 VL2_IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
VL2_SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
VL2_IIC_SCL=0;
delay_us(VL2_SPEED*2);
VL2_IIC_SCL=1;
receive<<=1;
if(VL2_READ_SDA)receive++;
delay_us(VL2_SPEED*2); //1
}
if (!ack)
VL2_IIC_NAck();//发送nACK
else
VL2_IIC_Ack(); //发送ACK
return receive;
}
//IIC写一个字节数据
u8 VL2_IIC_Write_1Byte(u8 SlaveAddress, u8 REG_Address, u8 data)
{
VL2_IIC_Start();
VL2_IIC_Send_Byte(SlaveAddress);
if(VL2_IIC_Wait_Ack())
{
VL2_IIC_Stop();//释放总线
return 1;//没应答则退出
}
VL2_IIC_Send_Byte(REG_Address);
VL2_IIC_Wait_Ack();
VL2_IIC_Send_Byte(data);
VL2_IIC_Wait_Ack();
VL2_IIC_Stop();
return 0;
}
//IIC读一个字节数据
u8 VL2_IIC_Read_1Byte(u8 SlaveAddress, u8 REG_Address,u8 *REG_data)
{
VL2_IIC_Start();
VL2_IIC_Send_Byte(SlaveAddress);//发写命令
if(VL2_IIC_Wait_Ack())
{
VL2_IIC_Stop();//释放总线
return 1;//没应答则退出
}
VL2_IIC_Send_Byte(REG_Address);
VL2_IIC_Wait_Ack();
VL2_IIC_Start();
VL2_IIC_Send_Byte(SlaveAddress|0x01);//发读命令
VL2_IIC_Wait_Ack();
*REG_data = VL2_IIC_Read_Byte(0);
VL2_IIC_Stop();
return 0;
}
//IIC写n字节数据
u8 VL2_IIC_Write_nByte(u8 SlaveAddress, u8 REG_Address,u16 len, u8 *buf)
{
VL2_IIC_Start();
VL2_IIC_Send_Byte(SlaveAddress);//发写命令
if(VL2_IIC_Wait_Ack())
{
VL2_IIC_Stop();//释放总线
return 1;//没应答则退出
}
VL2_IIC_Send_Byte(REG_Address);
VL2_IIC_Wait_Ack();
while(len--)
//while(*buf != '\0')
{
VL2_IIC_Send_Byte(*buf++);//发送buff的数据
VL2_IIC_Wait_Ack();
}
VL2_IIC_Stop();//释放总线
return 0;
}
//IIC读n字节数据
u8 VL2_IIC_Read_nByte(u8 SlaveAddress, u8 REG_Address,u16 len,u8 *buf)
{
VL2_IIC_Start();
VL2_IIC_Send_Byte(SlaveAddress);//发写命令
if(VL2_IIC_Wait_Ack())
{
VL2_IIC_Stop();//释放总线
return 1;//没应答则退出
}
VL2_IIC_Send_Byte(REG_Address);
VL2_IIC_Wait_Ack();
VL2_IIC_Start();
VL2_IIC_Send_Byte(SlaveAddress|0x01);//发读命令
VL2_IIC_Wait_Ack();
while(len)
{
if(len==1)
{
*buf = VL2_IIC_Read_Byte(0);
}
else
{
*buf = VL2_IIC_Read_Byte(1);
}
buf++;
len--;
}
VL2_IIC_Stop();//释放总线
return 0;
}
/**************************************以下是应用层调用的函数******************************************************/
//写多个数据
//address:地址
//index:偏移地址
//pdata:数据指针
//count:长度 最大65535
u8 I2C_SAND_BUFFER(u8 address, u8 index,u8 *pdata,u16 count)
{
u8 status = STATUS_OK;
if(VL2_IIC_Write_nByte(address,index,count,pdata))
{
status = STATUS_FAIL;
}
return status;
}
//读多个数据
//address:地址
//index:偏移地址
//pdata:数据指针
//count:长度 最大65535
u8 I2C_READ_BUFFER(u8 address,u8 index,u8 *pdata,u16 count)
{
u8 status = STATUS_OK;
if(VL2_IIC_Read_nByte(address,index,count,pdata))
{
status = STATUS_FAIL;
}
return status;
}
//写1个数据(单字节)
//address:地址
//index:偏移地址
//data:数据(8位)
u8 I2C_SAND_BYTE(u8 address,u8 index,u8 data)
{
u8 status = STATUS_OK;
status = I2C_SAND_BUFFER(address,index,&data,1);
return status;
}
main.c
#include "stm32f10x.h" //STM32头文件
#include "sys.h"
#include "delay.h"
#include "o2adc.h"
#include "io_i2c.h" //在i2c文件夹中的i2c.c/h是硬件I2C总线驱动,io_i2c.c/h是模拟I2C总线驱动
#include "stdio.h"
#include "oled0561.h"
int main (void){//主程序
u16 adcx1,adcx2;
float temp1,temp2,o2c,o2f;
u8 aa[5],bb[5];
delay_ms(100); //上电时等待其他器件就绪
RCC_Configuration(); //系统时钟初始化
I2C_Configuration();//I2C初始化
OLED0561_Init(); //OLED初始化
Adc_Init();
while(1){
adcx1=Get_Adc_Average(ADC_Channel_1 ,10);
temp1=(float)adcx1*(3.3/4096);
o2c = (temp1/3.3)*100;
sprintf((char*)aa,"O2C: %5.3f%%" ,o2c);
OLED_DISPLAY_8x16_BUFFER(0,2,aa);
adcx2=Get_Adc_Average(ADC_Channel_2 ,10);
temp2=(float)adcx2*(3.3/4096);
o2f = (temp2/3.3)*100;
sprintf((char*)bb,"O2F: %5.3f%%" ,o2f);
OLED_DISPLAY_8x16_BUFFER(3,0,bb);
}
}