您的位置:首页 > 其它

基于STM32的12864串行时序的实现

2015-07-21 22:47 302 查看
     12864液晶并口驱动程序用的比较多,但是考虑到有的时候单片机或者MCU的IO口有限时就可以使用串行驱动方法。以下是12864液晶串行时序图,下面就根据这个图来分析一下12864串行时序的实现,只有真正弄清楚了时序图才能真正了解串行传输的原理。



    

    从图上可以看出串行传输时需要用到CS,SCLK,SID三根信号线,但是由于CS是高电平有效,所以也可以把CS长接高电平,那样就只需要两根线就OK了,当然当使用12864串行模式时,PSB引脚必须接低电平,复位RST引脚可以悬空不接,因为12864内部有上电复位电路。

  由于数据是传输是以一个字节8bits为单位,所以下面贴出传输一个字节的函数实现

void Write_8bits(uint W_bits)
{
uint i,Temp_data;
for(i=0; i<8; i++)//总共移动八次,就可以把8bits数据全部传完
{
Temp_data = W_bits;
Temp_data <<= i;//把数据依次左移
if((Temp_data&0x80)==0) //判断对应位是否为0
{
CLRSID;// SID = 0;
CLRSCLK;//SCLK = 0;//在时钟的下降沿把数据传输出去
SETSCLK;// SCLK = 1;//置高电平,为下次传输做准备
}
else //对应位为1
{
SETSID;//SID = 1;
CLRSCLK;//SCLK = 0;
SETSCLK; //SCLK = 1;
}
}
}

    从时序图上可以看出,要想完整的把一个字节的数据传出去,需要传送三次才能实现,也就是需要传送三个字节,这三个字节分别是:命令控制字,字节的高四位+低四位0组成的字节,字节的低四位+高四位0组成的字节。

                                                                    命令控制字11111RWRS0

    RW代表读还是写液晶,为0代表写,为1代表读。RS代表写命令还是数据,为0代表写命令,为1代表写数据,其余6位固定。所以假设要向液晶写数据,就必须首先发送11111010,写命令就发送11111000。

  下面是程序的具体实现,这是关键!

void W_1byte(uchar RW, uchar RS, uchar W_data)
{
uint H_data,L_data,S_ID = 0xf8; //11111RWRS0
if(RW == 0)
{
S_ID &=~ 0x04;
}
else //if(RW==1)
{
S_ID |= 0X04;
}
if(RS == 0)
{
S_ID &=~ 0x02;
}
else //if(RS==1)
{
S_ID |= 0X02;
}
//以上是根据读写命令以及是发送数据还是命令来组合命令字
H_data = W_data;
H_data &= 0xf0; //屏蔽低4位的数据
L_data = W_data; //xxxx0000格式
L_data &= 0x0f; //屏蔽高4位的数据
L_data <<= 4; //xxxx0000格式
SETCS;//CS = 1; 时能发送
Write_8bits(S_ID); //发送命令字S_ID
Write_8bits(H_data); //发送H_data
Write_8bits(L_data); //发送L_data
CLRCS;//CS=0
}
//写入字符串
void LCD_write_string(uchar *s)
{
for(uint i=0;s[i]!='\0';i++)
W_1byte(0,1,s[i]);
}

//液晶初始化函数
void LCD_Init_12864(void)//液晶初始化程序
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
CLRPSB;//PSB=0 串行模式
OSTimeDly (40);//关于这个延时根据使用的单片机来决定我这里使用STM32 所以要加延时
W_1byte(0,0,0x30);//功能设置 8位数据,基本指令
OSTimeDly (40);
W_1byte(0,0,0x02); //地址归位
OSTimeDly (40);
W_1byte(0,0,0x06); //游标及显示右移一位
OSTimeDly (40);
W_1byte(0,0,0x0c); //显示状态 ON,游标OFF,反白OFF
OSTimeDly (40);
W_1byte(0,0,0x01); //清除显示
OSTimeDly (40);
W_1byte(0,0,0x81);//设置写入地址
LCD_write_string("STM32 ADC");
}
//附上一个实用的程序:把数字转换成字符串,n是转换的精度,即是字符串'.'后有几位小数
//有的时候要把AD采样得到的浮点型转换成字符串在液晶上显示,这个函数就非常有用
int ftoa(char *str, float num, int n)
{
int sumI;
float sumF;
int temp;
int count = 0;
char *p;
char *pp;
if(str == NULL) return -1;
p = str;

if(num < 0)
{
num = 0 - num;
}
sumI = (int)num; //sumI is the part of int
sumF = num - sumI; //sumF is the part of float

do
{
temp = sumI % 10;
*(str++) = temp+48;
}while((sumI = sumI /10) != 0);
pp = str;
pp--;
while(p < pp)
{
*p = *p + *pp;
*pp = *p - *pp;
*p = *p -*pp;
p++;
pp--;
}
*(st
r++) = '.';

do
{
tem
p = (int)(sumF*10);
*(str++) = temp+48;
if((++count) == n)
break;
sumF = sumF*10 - temp;
}while(!(sumF > -0.000001 && sumF < 0.000001));
*str='\0';
return 0;
}

//12864.h 12864头文件
#include
#define uchar CPU_INT08U
#define uint CPU_INT16U
#define SETCS GPIO_SetBits(GPIOC,GPIO_Pin_9) //CS PC.9
#define SETSID GPIO_SetBits(GPIOC,GPIO_Pin_10) //SID PC.10
#define SETSCLK GPIO_SetBits(GPIOC,GPIO_Pin_11) //SCLK PC.11
#define SETPSB GPIO_SetBits(GPIOC,GPIO_Pin_12) //PSB PC.12
#define CLRCS GPIO_ResetBits(GPIOC,GPIO_Pin_9)
#define CLRSID GPIO_ResetBits(GPIOC,GPIO_Pin_10)
#define CLRSCLK GPIO_ResetBits(GPIOC,GPIO_Pin_11)
#define CLRPSB GPIO_ResetBits(GPIOC,GPIO_Pin_12)
void W_1byte(uchar RW, uchar RS, uchar W_data);
void LCD_Init_12864(void);
int ftoa(char *str, float num, int n);
void LCD_write_string(u8 *s);
//主函数 实现功能STM32 ADC采样 在液晶上显示
#include "12864.h"
#define ADC1_DR_Address ((uint32_t)0x4001244C) //ADC数据寄存器的基地址
USART_InitTypeDef USART_InitStructure; //串口、ADC、DMA声明
ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure; // 注:ADC为12位模数转换器,只有ADCConvertedValue的低12位有效
uint16_t ADCConvertedValue;
void ADC_GPIO_Configuration(void);
static void Delay_ARMJISHU(__IO uint32_t nCount)
{
for (; nCount != 0; nCount--);
}
uchar tab1[]="0123456789";
int main(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
u16 ADCConvertedValueLocal, Precent = 0, Voltage = 0;
ADC_GPIO_Configuration();
//Delay_ARMJISHU(1000000);//延时 上电复位 不然需要手动复位
LCD_Init_12864();//液晶初始化程序
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA时钟

DMA_DeInit(DMA1_Channel1); //开启DMA1的第一通道
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; //DMA对应的外设基地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValue; //内存存储基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //DMA的转换模式为SRC模式,由外设搬移到内存
DMA_InitStructure.DMA_BufferSize = 1;//DMA缓存大小,1个
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //接收一次数据后,设备地址禁止后移
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; //关闭接收一次数据后,目标内存地址后移
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //定义外设数据宽度为16位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //DMA搬移数据尺寸,HalfWord就是为16位
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //转换模式,循环缓存模式。
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA优先级高
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //M2M模式禁用
DMA_Init(DMA1_Channel1, &DMA_InitStructure);

DMA_Cmd(DMA1_Channel1, ENABLE);

ADC_GPIO_Configuration();

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //独立的转换模式 ADC_DUALMOD[3:0]=0000;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;//开启扫描模式 ADC_SCAN=1;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//开启连续转换模式 ADC_CONT=1;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//ADC外部开关,关闭状态 ; 软件转换 ADC_EXTSEL[2:0]=111;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//对齐方式,ADC为12位中,右对齐方式 ADC_ALIGN=0;
ADC_InitStructure.ADC_NbrOfChannel = 1;//开启通道数,1个 ADC_SQR1[23:20]=0000;
//ADC_SQR1[23:20] 设置通道数目的选择
ADC_Init(ADC1, &ADC_InitStructure);

ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 1, ADC_SampleTime_55Cycles5);
//ADC_SMPR2 ADC_SMPR1 设置每个通道的采样时间
//ADC_SQR1[19:0]DC_SQR1[29:0]DC_SQR3[29:0] 设置对应通道的转换顺序 适用于多通道采样
//ADC通道组, 第9个通道 采样顺序1,转换时间

ADC_DMACmd(ADC1, ENABLE); //ADC命令,使能 ADC_ADON=1

ADC_Cmd(ADC1, ENABLE); //开启ADC1 ADC_DMA=1

ADC_ResetCalibration(ADC1); //重新校准

while(ADC_GetResetCalibrationStatus(ADC1)); //等待重新校准完成

ADC_StartCalibration(ADC1); //开始校准 ADC_RSTCAL=1; 初始化校准寄存器

while(ADC_GetCalibrationStatus(ADC1)); //等待校准完成 ADC_CAL=0;

ADC_SoftwareStartConvCmd(ADC1, ENABLE); //连续转换开始,ADC通过DMA方式不断的更新RAM区。
//ADC_SWSTART=1 开始规则转换 切记 软件触发也属于外部事件 要设置 ADC_EXTTRIG=1
while (1)
{
ADCConvertedValueLocal = ADCConvertedValue;
Precent = (ADCConvertedValueLocal*100/0x1000);//算出百分比
Voltage = Precent*33; //3.3V的电平,计算等效电平
W_1byte(0,0,0x91);
W_1byte(0,1,tab1[Precent/10]);
W_1byte(0,1,tab1[Precent]);
W_1byte(0,1,'%');
W_1byte(0,1,' ');
W_1byte(0,1,tab1[Voltage/1000]);
W_1byte(0,1,'.');
W_1byte(0,1,tab1[(Voltage00)/100]);
W_1byte(0,1,tab1[(Voltage0)/10]);
W_1byte(0,1,'V');
}
}
void ADC_GPIO_Configuration(void) //ADC配置函数
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOA, ENABLE); //使能ADC和GPIOC时钟
//PB1 作为模拟通道输入引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //管脚1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //输入模式
GPIO_Init(GPIOB, &GPIO_InitStructure); //GPIO组

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: