思路,用stc8a的P10,P11串口二,串口2的波特率用的是定时器2产生,9600,定时器1作为串口监视器,监事接收的信息。
大概隔300ms监视一次,注意。
然后提取串口的缓冲的信息。进行处理,判断等等
stc端的程序
#include "stc8a8k.h"
#include "delay.h"
#include "oled.h"
#include "stdio.h" //sprintf函数
#include "usart2.h" //串口2是P10_RXD2 .P11_TXD2管脚
//*************************串口变量,和UART2.C一致,不能改***************************
bit flagFrame = 0; //帧接收完成标志,即接收到一帧新数据
bit flagTxd = 0; //单字节发送完成标志,用来替代TXD中断标志位
unsigned char cntRxd = 0; //接收字节计数器
unsigned char pdata bufRxd[64]; //接收字节缓冲区
//*************************************************************************
//************************************************不能删除
//因为其他单片机传来的数据存在小数浮点数,所以这里设置一个共用体,方便一个个字节接收之后,
//转换成浮点数。
//共用体
// union 共用体名{
// 成员列表
// };
union f_data
{
float fdata;
unsigned char cdata[4];
};
//单精度的浮点数,一个浮点数,是四个字节,两个同一个内存空间放数据,便于拆分字节
union f_data floatdata0; //定义一个变量,放在这个空间,这个是全局变量
//*************************************************************
//************************************************不能删除
//因为其他单片机传来的数据存在整型,所以这里设置一个共用体,方便一个个字节接收之后,
//转换成整型。
//共用体
// union 共用体名{
// 成员列表
// };
union int_data
{
int intdata;
unsigned char cdata[2];
};
//整型,是2个字节,两个同一个内存空间放数据,便于拆分字节
//举例定义一个int变量,后面可以参照这个定义
//union int_data int0 //定义一个变量,放在这个空间,这个是全局变量**************
//*************************************************************
//传递的数据格式————————————————————————————
//帧头+功能码
// +浮点数0字节1+浮点数0字节2+浮点数0字节3+浮点数0字节4
// +浮点数1字节1+浮点数1字节2+浮点数1字节3+浮点数1字节4
// +整型数0字节1+整型数0字节2
// +整型数1字节1+整型数1字节2
// +字符型1字节1
// +字符型2字节1
//+帧尾
//+校验和(这里暂时不用校验和)
//举例说明:
//openmv摄像头,检测到某个东西的中心坐标为3.15,4.56,直径为12,颜色为红色(代号200),发送字符10,字符s
//总共是
//帧头+功能码+3.15+4.56+12+200+10+‘s’+帧尾
//由于浮点数占据四个字节,在网上http://lostphp.com/hexconvert/,IEEE 754浮点数十六进制相互转换(32位,四字节,单精度)
//十位数,输入3.15,得到对应的四字节为40 49 99 99(就是0x40+0x49+0x99+0x99)四个字节,
//输入4.56,得到对应四个字节40 91 EB 85,就是(0x40+0x91+0xeb+0x85)四个字节
//所以发送的字节为:
//帧头+功能码+(0x40+0x49+0x99+0x99)+(0x40+0x91+0xEB+0x85)+(0x00+0x0c)+(0x00+0xC8)+0x0a+'s'(对应ascii码)+帧尾
//上述的括号,是意思是说,这是一个数据,只不过是一个个字节发过来。不发送括号
//***********注意:包括帧头,帧尾,总共是17个字节;
//帧尾是16号,从0计算,0-16共17个字节
//现在51需要利用串口接收上面的数据,然后放到对应的变量中,显示出来,并且用来指导后面的其他动作,
//比如让机械手跑到3.15,4.56这个坐标等等。
//将串口接收的数据,放到对应变量里面:如果数据格式,变量等发生变化,也要对应的进行变化
//比如多了一个浮点型,也是按照上面分析的一样,定义多一个变量,后面就能使用了。
#define FrameLen 17 //一共17个字节
unsigned char StartChar=0xab; //帧头定义为0xab
//功能码 0x01----接收的是信息1:任务二维码;123+321
//0x02,接收的是信息2:颜色信息
//0x03, 接收的是信息3:xxxx
//0x04: 接收的是信息4:xxx...可以根据实际情况,继续添加不同的作用
//接收缓冲区的信息;
unsigned char FunCode=0x00;//功能码
#define Fun1 0x31
#define Fun2 0x32
#define Fun3 0x33
#define Fun4 0xd1 //openmv发送过来的二维码确认代码0xd1=209
unsigned char Message1[16]={0x00};//存放任务二维码:123+321
union f_data xzuobiao;
union f_data yzuobiao;
union int_data zhijing;
union int_data yanse;
unsigned char char0;
unsigned char char1;
unsigned char EndChar1=0xba;//帧尾定义为0xba(坐标的帧尾)
unsigned char EndChar2=0xba;//帧尾定义为0xba(任务二维码的帧尾)
unsigned char CheckSumNum=0x00;//校验和,这里不用到校验和,后面添加
unsigned char flagCode=0;
//*************************************************************************
void UartAction(unsigned char *buf, unsigned char len);//串口接收到数据后,执行对应的命令
void ConfigTimer0();//定时器0配置,1ms定时时间
//所以需要ascii码,实际计算是利用数值进行计算的;
unsigned char intchar[2]={0x00,0x00};//给hex--char用
//******************************************************************
//******************************************************************
void portmode();
unsigned long Str_Long(char *str,unsigned char len) ;
//******************************************************************
//******************************************************************
//**************************************************************************
void main()
{
unsigned char ix=0;
floatdata0.fdata=3.15;//这个union里面的fdata
portmode();
ConfigTimer0();
OLED_Init();
UART2_init();
OLED_ShowString(0,1,"bbb");
IE2 =0x01; // 开串口2中断
EA = 1; // 开总中断
delay_tms(5000);
//延时10s,之后开始发送,检测二维码的数据,直到得到串口发来的数据
flagCode=1;
//直到接收到openmv模块发来的确认信息,否则不断发送
//确认信息:0xab+0xd1+0xba+校验码
//
while(flagCode)//flagCode=0是在等待上位机发过来指令
{
UART_Send_Byte(0xab);
delay_tms(2);
UART_Send_Byte(0x11);
delay_tms(2);
UART_Send_Byte(0xba);//(0xab+0x11+0xba)%256
delay_tms(2);
UART_Send_Byte((0xab+0x11+0xba)%256);//发送校验码
delay_tms(2);
// OLED_ShowString(100,4,"998");
delay_tms(100);
UartDriver();//读取串口数据,并且执行串口执行函数;
}
// OLED_ShowString(0,3,"OKOKOK");
delay_tms(100);
while(1)
{
// OLED_ShowString(100,5,"XXX"); // OLED_ShowString(10,3,"Fun4OK");
UartDriver();//读取串口数据,并且执行串口执行函数;
}
OLED_ShowString(100,4,"oouX");
}
//****************************端口模式设置,准双向口
void portmode()
{
P0M1=0x00;P0M0=0x00;
P1M1=0x00;P1M0=0x00;
P2M1=0x00;P2M0=0x00;
P3M1=0x00;P3M0=0x00;
P4M1=0x00;P4M0=0x00;
P5M1=0x00;P5M0=0x00;
P6M1=0x00;P6M0=0x00;
P7M1=0x00;P7M0=0x00;
}
/*********************串口动作函数,根据接收到的命令帧执行响应的动作
buf-接收到的命令帧指针,len-命令帧长度 */
void UartAction(unsigned char *buf, unsigned char len)
{
unsigned char disbuf[9];//用于OLED显示浮点数开辟的缓冲区
long temp0=0;
//帧头肯定对,因为在接收函数里面,如果帧头不对,是不接受数据的,
//void Uart2Isr() interrupt 8 using 1 里面,不然进入不了这个函数
//将接收的数据,放到对应的变量里面;
//判断一下帧尾,看是不是发送完数据
//判别第二个功能码,从而知道传来的是什么信息。
FunCode=*(buf+1);
switch(FunCode)
{
//*********************************************************
case 0x31: //0x01任务二维码:123+321,第一次搬运+第二次搬运
// OLED_ShowChar(0,5,FunCode);
// OLED_ShowNum(15,2,FunCode,3,12);//209 ac
OLED_ShowChar(30,5,'k');
Message1[0]=*(buf+2) ;
Message1[1]=*(buf+3) ;
Message1[2]=*(buf+4) ;
Message1[3]=*(buf+5) ;
Message1[4]=*(buf+6) ;
Message1[5]=*(buf+7) ;
Message1[6]=*(buf+8) ;
// //openmv中发来的直接包括了+0x30,就是char类型
OLED_ShowChar(0,4, Message1[0]);
OLED_ShowChar(8,4, Message1[1]);
OLED_ShowChar(16,4, Message1[2]);
OLED_ShowChar(24,4, Message1[3]);
OLED_ShowChar(32,4, Message1[4]);
OLED_ShowChar(40,4, Message1[5]);
OLED_ShowChar(48,4, Message1[6]);
break;
// //判断有没有帧尾;
// if(EndChar1==*(buf+10))//帧尾是不是相等,数据有没有发送完成
// //**************************功能1:任务码
// {
// Message1[0]=*(buf+2) ;
// Message1[1]=*(buf+3) ;
// Message1[2]=*(buf+4) ;
// Message1[3]=*(buf+5) ;
// Message1[4]=*(buf+6) ;
// Message1[5]=*(buf+7) ;
// Message1[6]=*(buf+8) ;
// //第九个是空格,字符串发送的话,会多一个空格
// //第十个是帧尾
//
// }
// break;
//*********************************************************
case Fun2: //颜色信息
Message1[0]=*(buf+2) ;
break;
//*********************************************************
case Fun3:
//判断有没有帧尾,是不是完整的命令,这里的15,是说长度-1
//帧头:*(buf+0)
//功能码:*(buf+1)
//浮点数0:*(buf+2) *(buf+3) *(buf+4) *(buf+5)
//浮点数1: *(buf+6) *(buf+7) *(buf+8)*(buf+9)
//整型0: *(buf+10) *(buf+11)
//整型1: *(buf+12) *(buf+13)
//字符0: *(buf+14)
//字符1: *(buf+15)
//帧尾: *(buf+16)
if(EndChar1==*(buf+(FrameLen-1)))//帧尾是不是相等,数据有没有发送完成
{
//PC先来的高字节,放在在51的低位,大端模式和小端模式的区别,百度下
xzuobiao.cdata[0]=*(buf+1);
xzuobiao.cdata[1]=*(buf+2);
xzuobiao.cdata[2]=*(buf+3);
xzuobiao.cdata[3]=*(buf+4);
//PC先来的高字节,放在在51的低位,大端模式和小端模式的区别,百度下
yzuobiao.cdata[0]=*(buf+5);
yzuobiao.cdata[1]=*(buf+6);
yzuobiao.cdata[2]=*(buf+7);
yzuobiao.cdata[3]=*(buf+8);
//PC先来的高字节,放在在51的低位,大端模式和小端模式的区别,百度下
zhijing.cdata[0]=*(buf+9);
zhijing.cdata[1]=*(buf+10);
//PC先来的高字节,放在在51的低位,大端模式和小端模式的区别,百度下
yanse.cdata[0]=*(buf+11);
yanse.cdata[1]=*(buf+12);
char0=*(buf+13);
char1=*(buf+14);
//显示接收的数据,看下对不 对
sprintf(disbuf,"%0.2f",xzuobiao.fdata);
OLED_ShowString(0,0,disbuf);
sprintf(disbuf,"%0.2f",yzuobiao.fdata);
OLED_ShowString(64,1,disbuf);
OLED_ShowNum(0,2,zhijing.intdata,5,12);
OLED_ShowNum(0,3,yanse.intdata,5,12);
OLED_ShowChar(0,4,char0);
OLED_ShowChar(48,4,char1);
}
break;
//********************************************************
case 0xd1://接收到0xd1
//判断一下帧尾是不是相等
Message1[0]=*(buf+2) ; //0xba
Message1[1]=*(buf+3) ; //校验码 Message1[1]=*(buf+3) ; //校验码
//判断帧尾是不是相等
if(Message1[0]==0xba)
if(Message1[1]==(0xab+0xd1+0xba)%256); //校验码是不是相等
flagCode=0;//二维码扫描指令收到,停止发送二维码指令
OLED_ShowChar(30,5,'m');
temp0=Str_Long(Message1,5) ;
// OLED_ShowNum(32,0, temp0,5,12);//得到对应的任务号
// OLED_ShowString(10,3,"Fun4OK");
// OLED_ShowNum(100,0,Message1[0],3,12);//得到对应的任务号0xba==186
// OLED_ShowChar(100,5,FunCode);
FunCode=0x00;
break;
//*********************************************************
default:break;
}
}
/* 配置并启动T0,ms-T0定时时间 */
void ConfigTimer0()
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xCD; //设置定时初值
TH0 = 0xD4; //设置定时初值
TF0 = 0; //清除TF0标志
ET0 = 1; //使能T0中断
TR0 = 1; //定时器0开始计时
}
/* T0中断服务函数,执行串口接收监控和蜂鸣器驱动 */
void InterruptTimer0() interrupt 1
{
TL0 = 0xCD; //设置定时初值
TH0 = 0xD4; //设置定时初值
UartRxMonitor(1); //串口接收监控
}
// /******************************************************************
// 功能:将一个字符串转为32位长整型变量,比如"1234"转为1234
// 参数:str:指向待转换的字符串
// 返回:转换后的数值
// ******************************************** **********************/
// unsigned long Str_Long(char *str)
// {
// unsigned long temp=0;
// unsigned long fact=1;
// unsigned char len=strlen(str); // <string.h>头文件包含strlen()函数
// unsigned char i; // strlen()函数计算的字符串长度不包含最后一个空字符(值0)
// for(i=len;i>0;i--)
// {
// temp+=((str[i-1]-0x30)*fact); // 数组下标从0开始
// fact*=10;
// }
// return temp;
// }
/******************************************************************
功能:将一个字符串转为32位长整型变量,比如"1234"转为1234
参数:str:指向待转换的字符串
返回:转换后的数值
******************************************** **********************/
unsigned long Str_Long(char *str,unsigned char len)
{
unsigned long temp=0;
unsigned long fact=1;
// unsigned char len=strlen(str); // <string.h>头文件包含strlen()函数
unsigned char i; // strlen()函数计算的字符串长度不包含最后一个空字符(值0)
for(i=len;i>0;i--)
{
temp+=((str[i-1]-0x30)*fact); // 数组下标从0开始
fact*=10;
}
return temp;
}
uart2.h
#include "stc8a8k.h"
#define FOSC 11059200UL
#define BRT (65536 - FOSC / 9600 / 4)
extern unsigned char num23;
//使用定时器2做波特率发生器
//串口2:P10 Rxd2;P11 TXD2
#define S2_S0 0x01 //P_SW2.0
//***********************************************************在主函数中定义,这里是引用别个文件定义的变量
extern bit flagFrame ; //帧接收完成标志,即接收到一帧新数据
extern bit flagTxd ; //单字节发送完成标志,用来替代TXD中断标志位
extern unsigned char cntRxd ; //接收字节计数器
extern unsigned char pdata bufRxd[64]; //接收字节缓冲区
//*********************************************************************
void UART2_init(void);//初始化,9600,1T模式
unsigned char CheckSum(unsigned char *ptr, unsigned char len);//校验和
void sendcombytesUART2(unsigned char *ptr, unsigned char len);
void UartRxMonitor(unsigned char ms);
extern void UartAction(unsigned char *buf, unsigned char len);
void UartDriver();
void UART_Send_Byte(unsigned char dat);
uart2.c
#include "usart2.h"
#include "oled.h"
#include "delay.h"
#include <string.h>
extern unsigned char StartChar;//帧头
void UART2_init(void)
{
S2CON = 0x10; //8位数据,可变波特率
AUXR |= 0x04; //定时器2时钟为Fosc,即1T
T2L = 0xE0; //设定定时初值
T2H = 0xFE; //设定定时初值
AUXR |= 0x10; //启动定时器2
}
//##################################################################################
void Uart2Isr() interrupt 8 using 1 // 串行口2中断函数
{
//发送
if(S2CON&0x02) // 0x02=0000 0010,发送中断标志 S2TI=1
{
S2CON&=0xFD; // 0xFD=1111 1101,清零发送中断标志 S2TI=0,
}
//接受到1个字节//接收到新字节
else if(S2CON&0x01) // 0x01=0000 0001,接收中断标志 S2RI=1
{
S2CON&=0xFE; // 0xFE=1111 1110,清零接收中断标志 S2RI=0,
// OLED_ShowString(0,4,"rees");
// delay_tms(5);
// num23 = S2BUF;
// OLED_ShowChar(110,3,'m');
// num23++;
// S2BUF = num23; // 启动数据发送过程
if (cntRxd < sizeof(bufRxd)) //接收缓冲区尚未用完时,
{ //保存接收字节,并递增计数器
if(cntRxd==0) //判断第一个字节
{
bufRxd[cntRxd] = S2BUF;//将第一个的字节,放到缓冲区
if(bufRxd[cntRxd]==StartChar)//判断是不是帧头
{
cntRxd=1;//是帧头,开始接受
}
else
{
cntRxd=0;//不是的话,等到接受到帧头
}
}
else//后面开始不断接受
{
bufRxd[cntRxd] = S2BUF;
cntRxd++;
}
}
}
}
/*********************************************/
unsigned char CheckSum(unsigned char *ptr, unsigned char len)
{
unsigned char i;
unsigned char a;
unsigned int Value=0;
for(i=0;i<len;i++) // len结束后第一个字节为接收到的校验和
{
Value = Value + ptr[i];
}
a=Value; // 长送短,传送完整低字节
return(a);
}
/*********************************************/
//发送一帧完整数据
void sendcombytesUART2(unsigned char *ptr, unsigned char len)
{
unsigned char i;
for(i=0;i<len;i++)
{
S2BUF=*(ptr+i);
while(S2CON&0x02);
S2CON&=0xFD;
}
}
/* 串口数据读取函数,buf-接收指针,len-指定的读取长度,返回值-实际读到的长度 */
unsigned char UartRead(unsigned char *buf, unsigned char len)
{
unsigned char i;
if (len > cntRxd) //指定读取长度大于实际接收到的数据长度时,
{ //读取长度设置为实际接收到的数据长度
len = cntRxd;
}
for (i=0; i<len; i++) //拷贝接收到的数据到接收指针上
{
*buf++ = bufRxd[i];
}
cntRxd = 0; //接收计数器清零
return len; //返回实际读取长度
}
/* 串口接收监控,由空闲时间判定帧结束,需在定时中断中调用,ms-定时间隔 */
void UartRxMonitor(unsigned char ms)
{
static unsigned char cntbkp = 0;
static unsigned char idletmr = 0;
if (cntRxd > 0) //接收计数器大于零时,监控总线空闲时间
{
if (cntbkp != cntRxd) //接收计数器改变,即刚接收到数据时,清零空闲计时
{
cntbkp = cntRxd;
idletmr = 0;
}
else //接收计数器未改变,即总线空闲时,累积空闲时间
{
if (idletmr < 30) //空闲计时小于30ms时,持续累加
{
idletmr += ms;
if (idletmr >= 30) //空闲时间达到30ms时,即判定为一帧接收完毕
{
flagFrame = 1; //设置帧接收完成标志
}
}
}
}
else
{
cntbkp = 0;
}
}
/* 串口驱动函数,监测数据帧的接收,调度功能函数,需在主循环中调用 */
void UartDriver()
{
unsigned char len;
unsigned char pdata buf[40];
//串口接收监控中改变
if (flagFrame) //有命令到达时,读取处理该命令
{
flagFrame = 0;
len = UartRead(buf, sizeof(buf)); //将接收到的命令读取到缓冲区中
UartAction(buf, len); //传递数据帧,调用动作执行函数
}
}
/**************************************************************************
功能:STC15单片机的串口发送字节的函数
参数:dat:要发送的一个字节
IE2 XX ET4 ET3 ES4 ES3 ET2 ESPI ES2
0 0 0 0 0 0 0 1
ES2=1
IE2 &=~0x01
**************************************************************************/
void UART_Send_Byte(unsigned char dat)
{
IE2 &=~0x01; // 使用查询发送结束方式,禁止中断干预 IE2 = ES2; 0x01 //使能串口中断
S2BUF = dat;
while(S2CON&0x02);
S2CON&=0xFD;
// while(!TI);
// TI=0; //此句可以不要,不影响后面数据的发送,只供代码查询数据是否发送完成
IE2 |=0x01;
}
/************************************************************************** S2BUF=*(ptr+i);
while(S2CON&0x02);
S2CON&=0xFD;
功能:STC15单片机的串口发送0d 0a ,即回车换行
注:此函数就是发送0d 0a这两个字节,在"串口助手"上会有回车换行的效果
**************************************************************************/
// void UART_Send_Enter()
// {
// UART_Send_Byte(0x0d); // 转义字符常量\r,ASCII码值(10进制)=13,光标移到本行行首
// UART_Send_Byte(0x0a); // 转义字符常量\n,ASCII码值(10进制)=10,光标移到下行行首
// }
/**************************************************************************
功能:16进制转ASCII码函数
**************************************************************************/
unsigned char Hex_ASCII(unsigned int hex,char *str)
{
unsigned char temp=0;
temp=((hex&0xf000)>>12); // 4位1表示范围0_9_A_F
str[0]=(temp>=10)?(temp-10+'A'):(temp+0x30);
// 0_9的ASCII码是0_9+ 0x30,
// A_F的ASCII码: A代表数值10,A的ASCII码是65,因此数值+55=ASCII
// 因此算式(temp-10+'A')=(temp-10+65)=(temp+55)
// 分析依据:ASCII码表
temp=((hex&0x0f00)>>8);
str[1]=(temp>=10)?(temp-10+'A'):(temp+0x30);
temp=((hex&0x00f0)>>4);
str[2]=(temp>=10)?(temp-10+'A'):(temp+0x30);
temp=((hex&0x000f)>>0);
str[3]=(temp>=10)?(temp-10+'A'):(temp+0x30);
str[4]=0; // 由于要使用KEIL自带的字符串处理函数处理,必须有结束标记。
return 0;
}
// /**************************************************************************
// 功能:51单片机的串口发送调试信息(二进制数据显示)
// 参数:dat:需要按2进制形式显示变量
// **************************************************************************/
// void UART_Send_binary(unsigned char dat)
// {
// unsigned char i;
// unsigned char a[17];
// for(i=0;i<8;i++)
// {
// a[i]=((dat<<i)&0x80)?'1':'0';
// }
// a[i]=0;
// for(i=0;i<strlen(a);i++)
// {
// UART_Send_Byte(a[i]);
// UART_Send_Byte(' ');
// }
// }
oled.h
//
// 功能描述 : OLED 4接口演示例程(51系列)
// 说明:
// ----------------------------------------------------------------
// GND 电源地
// VCC 接5V或3.3v电源
// D0 接P10(SCL)
// D1 接P11(SDA)
// RES 接P12
// DC 接P13
// CS 接P14
//******************************************************************************/
#ifndef __OLED_H
#define __OLED_H
#include "stc8a8k.h"
//OLED模式设置
//0:4线串行模式
//1:并行8080模式
#define OLED_MODE 0
#define SIZE 12
#define XLevelL 0x00
#define XLevelH 0x10
#define Max_Column 128
#define Max_Row 64
#define Brightness 0xFF
#define X_WIDTH 128
#define Y_WIDTH 64
//---------------------------------
// d0 d1 res dc cs
// scl sdin rst
//-----------------OLED端口定义----------------
// sbit OLED_SCLK= P0^0;
// sbit OLED_SDIN= P0^1;
// sbit OLED_RST=P0^2;
// sbit OLED_DC=P0^3;
// sbit OLED_CS=P0^4;
sbit OLED_SCLK= P7^4;
sbit OLED_SDIN= P7^5;
sbit OLED_RST=P7^6;
sbit OLED_DC=P7^7;
sbit OLED_CS=P4^3;
#define OLED_CMD 0 //写命令
#define OLED_DATA 1 //写数据
void OLED_SCLK_Clr();//CLK
void OLED_SCLK_Set();
void OLED_SDIN_Clr();//DIN
void OLED_SDIN_Set();
void OLED_RST_Clr();//RES
void OLED_RST_Set();
void OLED_DC_Clr();//DC
void OLED_DC_Set();
void OLED_CS_Clr();//CS
void OLED_CS_Set();
//OLED控制用函数
void delay_tmsOLED(unsigned int ms0); //@11.0592MHz--11-190-766us;11-195--785us;20--x--1000
void delay4us_tOLED(int us); //@11.0592MHz---4us
void OLED_WR_Byte(u8 dat,u8 cmd);
void OLED_Display_On(void);
void OLED_Display_Off(void);
void OLED_Init(void);
void OLED_Clear(void);
void OLED_DrawPoint(u8 x,u8 y,u8 t);
void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot);
void OLED_ShowChar(u8 x,u8 y,u8 chr);
void OLED_ShowNum(u8 x,u8 y,u16 num,u8 len,u8 size0);
void OLED_ShowString(u8 x,u8 y, u8 *p);
void OLED_Set_Pos(unsigned char x, unsigned char y);
void OLED_ShowFloatii(u8 x,u8 y,float num,u8 ii);
#endif
oled.c
// //---------------------------------
// // d0 d1 res dc cs
// // scl sdin rst
// //-----------------OLED端口定义----------------
// sbit OLED_SCLK= P0^0;
// sbit OLED_SDIN= P0^1;
// sbit OLED_RST=P0^2;
// sbit OLED_DC=P0^3;
// sbit OLED_CS=P0^4;
//******************************************************************************/
#include "oled.h"
#include "oledfont.h"
#if OLED_MODE==1
//向SSD1106写入一个字节。
//dat:要写入的数据/命令
//cmd:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 cmd)
{
DATAOUT(dat);
if(cmd)
OLED_DC_Set();
else
OLED_DC_Clr();
OLED_CS_Clr();
OLED_WR_Clr();
OLED_WR_Set();
OLED_CS_Set();
OLED_DC_Set();
}
#else
//向SSD1106写入一个字节。
//dat:要写入的数据/命令
//cmd:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 cmd)
{
u8 i;
if(cmd)
OLED_DC_Set();
else
OLED_DC_Clr();
delay4us_tOLED(1);
OLED_CS_Clr();
delay4us_tOLED(1);
for(i=0;i<8;i++)
{
OLED_SCLK_Clr();
delay4us_tOLED(1);
if(dat&0x80)
OLED_SDIN_Set();
else
OLED_SDIN_Clr();
OLED_SCLK_Set();
dat<<=1;
}
delay4us_tOLED(1);
OLED_CS_Set();
delay4us_tOLED(1);
OLED_DC_Set();
}
#endif
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)
{
u8 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);
} //更新显示
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示
//size:选择字体 16/12
void OLED_ShowChar(u8 x,u8 y,u8 chr)
{
unsigned char c=0,i=0;
c=chr-' ';//得到偏移后的值
if(x>Max_Column-1){x=0;y=y+2;}
OLED_Set_Pos(x,y+1);
for(i=0;i<6;i++)
OLED_WR_Byte(F6x8[c][i],OLED_DATA);
}
//m^n函数
u16 oled_pow(u8 m,u8 n)
{
u16 result=1;
while(n--)result*=m;
return result;
}
//显示2个数字
//x,y :起点坐标
//len :数字的位数
//size:字体大小,这里是12
//mode:模式 0,填充模式;1,叠加模式
//num:数值(0~4294967295);
void OLED_ShowNum(u8 x,u8 y,u16 num,u8 len,u8 size0)
{
u8 t,temp;
u8 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+((size0/2)+1)*t,y,' ');//这里我自己修改了一下。不如数据会重叠
continue;
}else enshow=1;
}
OLED_ShowChar(x+((size0/2)+1)*t,y,temp+'0'); //这里我自己修改了一下。不如数据会重叠
}
}
//显示一个字符号串
void OLED_ShowString(u8 x,u8 y,u8 *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++;
}
}
//初始化SSD1306
void OLED_Init(void)
{
//设置端口的IO模式,不同引脚不一样 ====================********%%% 注意修改
// sbit OLED_SCLK= P0^2;
// sbit OLED_SDIN= P0^3;
// sbit OLED_RST=P0^4;
// sbit OLED_DC=P2^0;
// sbit OLED_CS=P0^6;
//准双向口模式
// --------------------------
// P07 06 05 04 03 02 01 00
//P0M0 x 0 x 0 0 0 x x ===0xa3
//P0M1 x 0 x 0 0 0 x x ===0xa3
//准双向口模式
// --------------------------
// P27 26 25 24 23 22 21 20
//P2M0 x x x x x x x 0 ==0xfe
//P2M1 x x x x x x x 0 ==0xfe
P4M0 =0;//与操作 清零
P4M1 =0;
P7M0=0;
P7M1=0;
/
delay_tmsOLED(5);
OLED_RST_Set();
delay_tmsOLED(5);
OLED_RST_Clr();
delay_tmsOLED(5);
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);
}
//
void OLED_SCLK_Clr()//CLK
{
OLED_SCLK=0;
}
///
void OLED_SCLK_Set()
{
OLED_SCLK=1;
}
//
void OLED_SDIN_Clr()//DIN
{
OLED_SDIN=0;
}
void OLED_SDIN_Set()
{
OLED_SDIN=1;
}
//
void OLED_RST_Clr()//RES
{
OLED_RST=0;
}
/
void OLED_RST_Set()
{
OLED_RST=1;
}
///
void OLED_DC_Clr()//DC
{
OLED_DC=0;
}
/
void OLED_DC_Set()
{
OLED_DC=1;
}
///
void OLED_CS_Clr()//CS
{
OLED_CS=0;
}
///
void OLED_CS_Set()
{
OLED_CS=1;
}
//
void OLED_ShowFloatii(u8 x,u8 y,float num,u8 ii)
{
u8 i,j,mm;
float mmd;
i=x*8;//横轴每8个像素点,移位一个数字;
j=y;//纵轴,每个换到新的行
mm=8;//
mmd=0.125;//等于1/8=0.125
switch(ii)
{
case 43://1234.456
OLED_ShowNum(i,j,(int)(num/1000)%10,1,12); //
OLED_ShowNum(i+mm,j,(int)(num/100)%10,1,12); //i+8
OLED_ShowNum(i+2*mm,j,(int)(num/10)%10,1,12);//i+16
OLED_ShowNum(i+3*mm,j,(int)(num)%10,1,12);//i+16
//OLED_ShowString((i+3*mm)*mmd,j,".");//i+24
OLED_ShowString(i+4*mm,j,".");//i+24
OLED_ShowNum(i+5*mm,j,(int)(num*10)%10,1,12);//i+32
OLED_ShowNum(i+6*mm,j,(int)(num*100)%10,1,12);
OLED_ShowNum(i+7*mm,j,(int)(num*1000)%10,1,12);
break;
case 42://1234.45
OLED_ShowNum(i,j,(int)(num/1000)%10,1,12); //
OLED_ShowNum(i+mm,j,(int)(num/100)%10,1,12); //i+8
OLED_ShowNum(i+2*mm,j,(int)(num/10)%10,1,12);//i+16
OLED_ShowNum(i+3*mm,j,(int)(num)%10,1,12);//i+16
//OLED_ShowString((i+3*mm)*mmd,j,".");//i+24
OLED_ShowString(i+4*mm,j,".");//i+24
OLED_ShowNum(i+5*mm,j,(int)(num*10)%10,1,12);//i+32
OLED_ShowNum(i+6*mm,j,(int)(num*100)%10,1,12);
break;
case 33://123.456
OLED_ShowNum(i,j,(int)(num/100)%10,1,12); //
OLED_ShowNum(i+mm,j,(int)(num/10)%10,1,12); //i+8
OLED_ShowNum(i+2*mm,j,(int)(num*1)%10,1,12);//i+16
//OLED_ShowString((i+3*mm)*mmd,j,".");//i+24
OLED_ShowString(i+3*mm,j,".");//i+24
OLED_ShowNum(i+4*mm,j,(int)(num*100)%10,1,12);//i+32
OLED_ShowNum(i+5*mm,j,(int)(num*100)%10,1,12);
OLED_ShowNum(i+6*mm,j,(int)(num*1000)%10,1,12);
break;
case 32://123.45*100=12345 1,5
//1---12345/10000 2---12345/1000=12 3---12345/100=123
//4---12345/10=1234 5---12345%10
OLED_ShowNum(i,j,(int)(num/100)%10,1,12); //
OLED_ShowNum(i+mm,j,(int)(num/10)%10,1,12); //
OLED_ShowNum(i+2*mm,j,(int)(num*10)%10,1,12); //
//OLED_ShowString((i+3*mm)*mmd,j,".");//
OLED_ShowString(i+3*mm,j,".");//
OLED_ShowNum(i+4*mm,j,(int)(num*10)%10,1,12);
OLED_ShowNum(i+5*mm,j,(int)(num*100)%10,1,12);
break;
case 31:
//123.4====1234
OLED_ShowNum(i,j,(int)(num/100)%10,1,12); //
OLED_ShowNum(i+mm,j,(int)(num/10)%10,1,12); //
OLED_ShowNum(i+2*mm,j,(int)(num*1)%10,1,12); //
// OLED_ShowString((i+3*mm)*mmd,j,".");//
OLED_ShowString(i+3*mm,j,".");
OLED_ShowNum(i+4*mm,j,(int)(num*10)%10,1,12);
break;
case 23:
//12.345===12345
OLED_ShowNum(i,j,(int)(num/10)%10,1,12); //
OLED_ShowNum(i+mm,j,(int)(num*1)%10,1,12); //
// OLED_ShowString((i+2*mm)*mmd,j,".");//
OLED_ShowString(i+2*mm,j,".");
OLED_ShowNum(i+3*mm,j,(int)(num*10)%10,1,12);//
OLED_ShowNum(i+4*mm,j,(int)(num*100)%10,1,12);
OLED_ShowNum(i+5*mm,j,(int)(num*1000)%10,1,12);
break;
case 22:
//12.34---1234--
OLED_ShowNum(i,j,(int)(num/10)%10,1,12); //
OLED_ShowNum(i+mm,j,(int)(num)%10,1,12);//
// OLED_ShowString((i+2*mm)*mmd,j,".");//
OLED_ShowString(i+2*mm,j,".");
OLED_ShowNum(i+3*mm,j,(int)(num*10)%10,1,12);
OLED_ShowNum(i+4*mm,j,(int)(num*100)%10,1,12);
break;
case 21:
//12.3---123--
OLED_ShowNum(i,j,(int)(num/10)%10,1,12);//
OLED_ShowNum(i+mm,j,(int)(num)%10,1,12);
//OLED_ShowString((i+2*mm)*mmd,j,".");//
OLED_ShowString(i+2*mm,j,".");
OLED_ShowNum(i+3*mm,j,(int)(num*10)%10,1,12);
break;
case 13:
//1.234===1234
OLED_ShowNum(i,j,(int)(num)%10,1,12); //
// OLED_ShowString((i+mm)*mmd,j,".");//
OLED_ShowString(i+2*mm,j,".");
OLED_ShowNum(i+2*mm,j,(int)(num*10)%10,1,12);//
OLED_ShowNum(i+3*mm,j,(int)(num*100)%10,1,12);
OLED_ShowNum(i+4*mm,j,(int)(num*1000)%10,1,12);
break;
case 12:
//1.23===123
OLED_ShowNum(i,j,(int)(num)%10,1,12);//
// OLED_ShowString((i+mm)*mmd,j,".");//
OLED_ShowString(i+mm,j,".");
OLED_ShowNum(i+2*mm,j,(int)(num*10)%10,1,12);
OLED_ShowNum(i+3*mm,j,(int)(num*100)%10,1,12);
break;
case 11:
//1.2===12
OLED_ShowNum(i,j,(int)(num*10/10)%10,1,12);
//OLED_ShowString((i+mm)*mmd,j,".");//
OLED_ShowString(i+mm,j,".");
OLED_ShowNum(i+2*mm,j,(int)(num*10)%10,1,12);
break;
default :break;
}
}
//
void delay_tmsOLED(unsigned int ms0) //@11.0592MHz--11-190-766us;11-195--785us;20--x--1000
{ //
unsigned char i, j;
unsigned int tms;
for(tms=ms0;tms>0;tms--)
for(i=20;i>0;i--)
for(j=136;j>0;j--);
}
/
void delay4us_tOLED(int us) //@11.0592MHz---4us
{
int i;
for(i=us;i>0;i--);
}
delay.h
#ifndef __DELAY_H
#define __DELAY_H
void delay_tus(unsigned int tus);
void delay_tms(unsigned int tms);
#endif
delay.c
#include "delay.h"
void delay_tus(unsigned int tus)//@11.0592MHz
{
unsigned char i;
i = tus;
while (--i);
}
void delay_tms(unsigned int tms)
{
unsigned char i, j,ttt;
for(ttt=tms;ttt>0;ttt--)
{
i = 15;
j = 90;
do
{
while (--j);
} while (--i);
}
}