一、项目介绍
信号发生器在生产实践和科技领域中有着广泛的应用,各种波形曲线均可以用三角函数方程式来表示。能够产生多种波形,如三角波、锯齿波、矩形波(含方波)、正弦波的电路被称为函数信号发生器。函数信号发生器在电路实验和设备检测中具有十分广泛的用途,例如在通信、广播、电视系统中,都需要射频(高频)发射。这里的射频波就是载波,把音频(低频)、视频信号或脉冲信号运载出去,就需要能够产生高频的振荡器。在工业、农业、生物医学等领域内,如高频感应加热、熔炼、淬火、超声诊断、核磁共振成像等,都需要功率或大或小、频率或高或低的振荡器。函数信号发生器是各种测试和实验过程中不可缺少的工具,在通信、测量、雷达、控制、教学等领域应用十分广泛。不论是在生产、科研还是教学上,信号发生器都是电子工程师信号仿真实验的最佳工具。而且,信号发生器的设计方法多,设计技术也越来越先进, 随着我国经济和科技的发展, 对相应的测试仪器和测试手段也提出了更高的要求,信号发生器己成为测试仪器中至关重要的一类,因此开发信号发生器具有重大意义。
二、主程序流程图
对系统运行工作流程进行说明后,给出系统主程序流程。
设计思路:首先将所有配置进行初始化,为了消除干扰和提升仿真效率,我们将系统的工作状态分为两种,一种为调整状态,另一种为波形输出状态,使用一个开关的通断来调整。
系统主程序流程图如图4-1所示。
三、 Proteus软件仿真调试
正弦波
方波
三角波
锯齿波
四、 硬件调试
在实际电路中,我们可以将频率调整的快一点,但是要注意抗干扰问题,毕竟上面的都是理论值,模拟信号非常容易受到其他因素的干扰。所有配置,都必须跟程序里面完全一致,如果波形失真,或者频率不对,还应进行相对应的补偿。
五、 程序清单
#include "stm32f10x.h"
#include "sys.h"
#include "delay.h"
#include "12864.h"
#include "key4_4.h"
#include "timer.h"
#define KEY0 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10)//读取按键0
void Delay_Ms(u16 time);
/*************** 配置Switch用到的I/O口*******************/
void Init_GPIO_Switch(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
//关闭jtag,使能SWD,可以用SWD模式调试
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
//PC0
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//IO口速度为50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
//设置成输入
GPIO_Init(GPIOB, &GPIO_InitStructure);
//初始化PC0
}
/****************************************************************
*功能名称:main
*描述:主程序。
*输入:无
*输出:无
*返回:无
****************************************************************/
int main(void)
{
u8 i=0;
RCC_ClocksTypeDef RCC_Clocks; //初始化程序
RCC_Configuration(RCC_PLLMul_4); //8M*4 == 32M
RCC_GetClocksFreq(&RCC_Clocks); //获取片上时钟
Init_12864(); //初始化12864液晶
Key_Init();
Init_GPIO_Switch();
Init_GPIO_DAC0832();
Data0=25;
TIM3_Int_Init(50+Data0,320);
//频率:32000000/ 320 ==100 000 /100 == 1000 /50==20
LCD_P6x8Str(3,16," Sine Wave ");
LCD_P6x8Str(7,6*2,"Frequency: 15 Hz");
while (1)
{
if(KEY0)
{
if(i!=2)
{
__set_PRIMASK(1);
GPIO_ResetBits(GPIOB, ((uint16_t)0xC000));
}
Key_Test();
i=2;
}
else{
if(i!=5)
{
TIM3_Int_Init(50+Data0,320);
__set_PRIMASK(0); //使能TIMx外设
GPIO_ResetBits(GPIOB, ((uint16_t)0xC000));
}
i=5;
}
}
}
/*************** 定时器*******************/
#include "timer.h"
#include "math.h"
#define ADC_CS_WR(a) if (a)
GPIO_SetBits(GPIOB,GPIO_Pin_14);
else
GPIO_ResetBits(GPIOB,GPIO_Pin_14)
#define ADC_CS_WR2(a) if (a)
GPIO_SetBits(GPIOB,GPIO_Pin_15);
else
GPIO_ResetBits(GPIOB,GPIO_Pin_15)
#define PI 3.1415926f //圆周率
u8 mode; //模式:正弦波……
u16 freq; //频率
u8 time; //计次参数
u8 AM; //调幅
/*************** 配置DAC用到的I/O口*******************/
void Init_GPIO_DAC0832(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); // 使能PC端口时钟
GPIO_InitStructure.GPIO_Pin = ((uint16_t)0x03FF); //选择对应的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化PC端口
GPIO_SetBits(GPIOC, ((uint16_t)0x00FF)); // 高
GPIO_ResetBits(GPIOC, ((uint16_t)0x00FF)); // 低
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); // 使能PC端口时钟
GPIO_InitStructure.GPIO_Pin = ((uint16_t)0xC000); //选择对应的引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PC端口
GPIO_SetBits(GPIOC, ((uint16_t)0xC000)); // 高
GPIO_ResetBits(GPIOC, ((uint16_t)0xC000)); // 低
time=0;
ADC_CS_WR(0);
mode=0; //默认输出正弦波
freq=100; //默认频率
AM=255; //最大幅度
}
void DAC_0832_Data(uint8_t Data)
{
GPIO_ResetBits(GPIOC,~Data);
GPIO_SetBits(GPIOC,Data);
}
void sine_wave(u8 location)//输出正弦波
{
double x=(double)location/50*PI;//把0-100放缩到0-2派(pai,没有那个符号)
u8 y=(sin(x)*(AM/2)+(AM/2));//算出y,并放缩到0-254(因为ADC范围0-AM,芯片落后)
DAC_0832_Data(y);
}
void squ_wave(u8 location)//方……
{
if(location<50)
DAC_0832_Data(AM);
else
DAC_0832_Data(0);//这个简单
}
void tri_wave(u8 location)//三……
{
//为了简化,在单周期输出V字形
u8 y;
if(location<50)
y=(50-location)*AM/50;
else
y=(location-50)*AM/50;
DAC_0832_Data(y);
//偶函数,当然说奇函数也没错
}
void saw_wave(u8 location)//锯……
{
DAC_0832_Data(location*AM/100);
//用(100-location)也以变成反向锯齿
}
//通用定时器中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 计数到5000为500ms
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 10Khz的计数频率
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
TIM_ITConfig( //使能或者失能指定的TIM中断
TIM3, //TIM3
TIM_IT_Update ,
ENABLE //使能
);
// TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
TIM_Cmd(TIM3, ENABLE); //使能TIMx外设
// TIM_Cmd(TIM3, DISABLE);
}
void TIM3_IRQHandler(void) //TIM3中断
{
switch(mode)
{
case W_SINE:sine_wave((u8)(time*freq/100)%100);break;//计算出波的位置
case W_SQU:squ_wave((u8)((time*freq/100)%100));break;
case W_TRI:tri_wave((u8)((time*freq/100)%100));break;
case W_SAW:saw_wave((u8)((time*freq/100)%100));break;
}
time++;
if(time>=100)//计数100次
time=0;
}
#include "key4_4.h"
#include "delay.h"
#include "sys.h"
#include "12864.h"
#include "timer.h"
//8个引脚 4个为行 4个为列
//行输出端口定义
#define X1_GPIO_PORT GPIOB
#define X2_GPIO_PORT GPIOB
#define X3_GPIO_PORT GPIOB
#define X4_GPIO_PORT GPIOB
//列输入端口定义
#define Y1_GPIO_PORT GPIOB
#define Y2_GPIO_PORT GPIOB
#define Y3_GPIO_PORT GPIOB
#define Y4_GPIO_PORT GPIOB
//行输出引脚定义
#define X1_GPIO_PIN GPIO_Pin_0
#define X2_GPIO_PIN GPIO_Pin_1
#define X3_GPIO_PIN GPIO_Pin_2
#define X4_GPIO_PIN GPIO_Pin_3
//列输入引脚定义
#define Y1_GPIO_PIN GPIO_Pin_4
#define Y2_GPIO_PIN GPIO_Pin_5
#define Y3_GPIO_PIN GPIO_Pin_6
#define Y4_GPIO_PIN GPIO_Pin_7
//行输出时钟定义
#define X1_RCC RCC_APB2Periph_GPIOB
#define X2_RCC RCC_APB2Periph_GPIOB
#define X3_RCC RCC_APB2Periph_GPIOB
#define X4_RCC RCC_APB2Periph_GPIOB
//列输入时钟定义
#define Y1_RCC RCC_APB2Periph_GPIOB
#define Y2_RCC RCC_APB2Periph_GPIOB
#define Y3_RCC RCC_APB2Periph_GPIOB
#define Y4_RCC RCC_APB2Periph_GPIOB
//移植代码只需要修改上面的端口和引脚和时钟即可,下面的代码不用修改。
//矩阵键盘所用的8个引脚可连续可不连续,看实际需要和个人爱好自己定义。
unsigned char Y1,Y2,Y3,Y4;
void Key_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(X1_RCC|X2_RCC|X3_RCC|X4_RCC|Y1_RCC|Y2_RCC|Y3_RCC|Y4_RCC|RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
/*******************4行输出 *****************************/
GPIO_InitStructure.GPIO_Pin = X1_GPIO_PIN ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(X1_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = X2_GPIO_PIN ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(X2_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = X3_GPIO_PIN ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(X3_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Pin = X4_GPIO_PIN ;
GPIO_Init(X4_GPIO_PORT, &GPIO_InitStructure);
/******************* 4列输入 *******************/
GPIO_InitStructure.GPIO_Pin = Y1_GPIO_PIN ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(Y1_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = Y2_GPIO_PIN ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(Y2_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = Y3_GPIO_PIN ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(Y3_GPIO_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Pin = Y4_GPIO_PIN;
GPIO_Init(Y4_GPIO_PORT, &GPIO_InitStructure);
}
int Key_Scan(void)
{
uchar KeyVal;
GPIO_SetBits(X1_GPIO_PORT,X1_GPIO_PIN); //先让X1输出高
GPIO_SetBits(X2_GPIO_PORT,X2_GPIO_PIN); //先让X2输出高
GPIO_SetBits(X3_GPIO_PORT,X3_GPIO_PIN); //先让X3输出高
GPIO_SetBits(X4_GPIO_PORT,X4_GPIO_PIN); //先让X4输出高
if((GPIO_ReadInputDataBit(Y1_GPIO_PORT,Y1_GPIO_PIN)|GPIO_ReadInputDataBit(Y2_GPIO_PORT,Y2_GPIO_PIN)|GPIO_ReadInputDataBit(Y3_GPIO_PORT,Y3_GPIO_PIN)|GPIO_ReadInputDataBit(Y4_GPIO_PORT,Y4_GPIO_PIN))==0x0000)
return -1; //如果X1到X4全为零则没有按键按下
else
{
Delay_Ms(5); //延时5ms去抖动
if((GPIO_ReadInputDataBit(Y1_GPIO_PORT,Y1_GPIO_PIN)|GPIO_ReadInputDataBit(Y2_GPIO_PORT,Y2_GPIO_PIN)|GPIO_ReadInputDataBit(Y3_GPIO_PORT,Y3_GPIO_PIN)|GPIO_ReadInputDataBit(Y4_GPIO_PORT,Y4_GPIO_PIN))==0x0000)
return -1;
}
GPIO_ResetBits(X1_GPIO_PORT,X1_GPIO_PIN);
GPIO_ResetBits(X2_GPIO_PORT,X2_GPIO_PIN);
GPIO_ResetBits(X3_GPIO_PORT,X3_GPIO_PIN);
GPIO_SetBits(X4_GPIO_PORT,X4_GPIO_PIN);
Y1=GPIO_ReadInputDataBit(Y1_GPIO_PORT,Y1_GPIO_PIN);Y2=GPIO_ReadInputDataBit(Y2_GPIO_PORT,Y2_GPIO_PIN);
Y3=GPIO_ReadInputDataBit(Y3_GPIO_PORT,Y3_GPIO_PIN);Y4=GPIO_ReadInputDataBit(Y4_GPIO_PORT,Y4_GPIO_PIN);
if(Y1==1&&Y2==0&&Y3==0&&Y4==0)
KeyVal='*';
if(Y1==0&&Y2==1&&Y3==0&&Y4==0)
KeyVal=0;
if(Y1==0&&Y2==0&&Y3==0&&Y4==1)
KeyVal='D';
if(Y1==0&&Y2==0&&Y3==1&&Y4==0)
KeyVal='#';
while(((GPIO_ReadInputDataBit(Y1_GPIO_PORT,Y1_GPIO_PIN))|(GPIO_ReadInputDataBit(Y2_GPIO_PORT,Y2_GPIO_PIN))|(GPIO_ReadInputDataBit(Y3_GPIO_PORT,Y3_GPIO_PIN))|(GPIO_ReadInputDataBit(Y4_GPIO_PORT,Y4_GPIO_PIN))) > 0);
//等待按键释放
GPIO_SetBits(X1_GPIO_PORT,X1_GPIO_PIN);
GPIO_ResetBits(X2_GPIO_PORT,X2_GPIO_PIN);
GPIO_ResetBits(X3_GPIO_PORT,X3_GPIO_PIN);
GPIO_ResetBits(X4_GPIO_PORT,X4_GPIO_PIN);
Y1=GPIO_ReadInputDataBit(Y1_GPIO_PORT,Y1_GPIO_PIN);Y2=GPIO_ReadInputDataBit(Y2_GPIO_PORT,Y2_GPIO_PIN);
Y3=GPIO_ReadInputDataBit(Y3_GPIO_PORT,Y3_GPIO_PIN);Y4=GPIO_ReadInputDataBit(Y4_GPIO_PORT,Y4_GPIO_PIN);
if(Y1==1&&Y2==0&&Y3==0&&Y4==0)
KeyVal=1;
if(Y1==0&&Y2==1&&Y3==0&&Y4==0)
KeyVal=2;
if(Y1==0&&Y2==0&&Y3==1&&Y4==0)
KeyVal=3;
if(Y1==0&&Y2==0&&Y3==0&&Y4==1)
KeyVal='A';
while(((GPIO_ReadInputDataBit(Y1_GPIO_PORT,Y1_GPIO_PIN))|(GPIO_ReadInputDataBit(Y2_GPIO_PORT,Y2_GPIO_PIN))|(GPIO_ReadInputDataBit(Y3_GPIO_PORT,Y3_GPIO_PIN))|(GPIO_ReadInputDataBit(Y4_GPIO_PORT,Y4_GPIO_PIN))) > 0);
GPIO_ResetBits(X1_GPIO_PORT,X1_GPIO_PIN);
GPIO_SetBits(X2_GPIO_PORT,X2_GPIO_PIN);
GPIO_ResetBits(X3_GPIO_PORT,X3_GPIO_PIN);
GPIO_ResetBits(X4_GPIO_PORT,X4_GPIO_PIN);
Y1=GPIO_ReadInputDataBit(Y1_GPIO_PORT,Y1_GPIO_PIN);Y2=GPIO_ReadInputDataBit(Y2_GPIO_PORT,Y2_GPIO_PIN);
Y3=GPIO_ReadInputDataBit(Y3_GPIO_PORT,Y3_GPIO_PIN);Y4=GPIO_ReadInputDataBit(Y4_GPIO_PORT,Y4_GPIO_PIN);
if(Y1==1&&Y2==0&&Y3==0&&Y4==0)
KeyVal=4;
if(Y1==0&&Y2==1&&Y3==0&&Y4==0)
KeyVal=5;
if(Y1==0&&Y2==0&&Y3==1&&Y4==0)
KeyVal=6;
if(Y1==0&&Y2==0&&Y3==0&&Y4==1)
KeyVal='B';
while(((GPIO_ReadInputDataBit(Y1_GPIO_PORT,Y1_GPIO_PIN))|(GPIO_ReadInputDataBit(Y2_GPIO_PORT,Y2_GPIO_PIN))|(GPIO_ReadInputDataBit(Y3_GPIO_PORT,Y3_GPIO_PIN))|(GPIO_ReadInputDataBit(Y4_GPIO_PORT,Y4_GPIO_PIN))) > 0);
GPIO_ResetBits(X1_GPIO_PORT,X1_GPIO_PIN);
GPIO_ResetBits(X2_GPIO_PORT,X2_GPIO_PIN);
GPIO_SetBits(X3_GPIO_PORT,X3_GPIO_PIN);
GPIO_ResetBits(X4_GPIO_PORT,X4_GPIO_PIN);
Y1=GPIO_ReadInputDataBit(Y1_GPIO_PORT,Y1_GPIO_PIN);Y2=GPIO_ReadInputDataBit(Y2_GPIO_PORT,Y2_GPIO_PIN);
Y3=GPIO_ReadInputDataBit(Y3_GPIO_PORT,Y3_GPIO_PIN);Y4=GPIO_ReadInputDataBit(Y4_GPIO_PORT,Y4_GPIO_PIN);
if(Y1==1&&Y2==0&&Y3==0&&Y4==0)
KeyVal=7;
if(Y1==0&&Y2==1&&Y3==0&&Y4==0)
KeyVal=8;
if(Y1==0&&Y2==0&&Y3==1&&Y4==0)
KeyVal=9;
if(Y1==0&&Y2==0&&Y3==0&&Y4==1)
KeyVal='C';
while(((GPIO_ReadInputDataBit(Y1_GPIO_PORT,Y1_GPIO_PIN))|(GPIO_ReadInputDataBit(Y2_GPIO_PORT,Y2_GPIO_PIN))|(GPIO_ReadInputDataBit(Y3_GPIO_PORT,Y3_GPIO_PIN))|(GPIO_ReadInputDataBit(Y4_GPIO_PORT,Y4_GPIO_PIN))) > 0);
return KeyVal;
}
/************************************
按键表盘为: 1 2 3 A
4 5 6 B
7 8 9 C
- 0 # D
************************************/
u8 ee,Data0=0;
void Key_Test(void)
{
int num;
char Freq[3]={'�'};
num = Key_Scan();
if(ee!=num)
switch(num)
{
case 0: LCD_P6x8Str(1,1,"0"); break;
case 1: LCD_P6x8Str(1,1,"1"); break;
case 2: LCD_P6x8Str(1,1,"2"); break;
case 3: LCD_P6x8Str(1,1,"3"); break;
case 4: LCD_P6x8Str(1,1,"4"); break;
case 5: LCD_P6x8Str(1,1,"5"); break;
case 6: LCD_P6x8Str(1,1,"6"); break;
case 7: LCD_P6x8Str(1,1,"7"); break;
case 8: LCD_P6x8Str(1,1,"8"); break;
case 9: LCD_P6x8Str(1,1,"9"); break;//
case'A':LCD_P6x8Str(1,1,"A");
mode=0;LCD_P6x8Str(3,16," Sine Wave "); break;
case'B':LCD_P6x8Str(1,1,"B");
mode=1;LCD_P6x8Str(3,16," Square wave "); break;
case'C':LCD_P6x8Str(1,1,"C"); mode=2;LCD_P6x8Str(3,16,"Ttiangular wave"); break;
case 'D': LCD_P6x8Str(1,1,"D");
mode=3;LCD_P6x8Str(3,16," Sawtooth Wave ");
break;
case '#': LCD_P6x8Str(1,1,"#");
if(Data0>=5)Data0-=5;
Freq[0]=(20-Data0/5)/10+'0';
Freq[1]=(20-Data0/5)%10+'0';
LCD_P6x8Str(7,6*13,Freq);
break;
case ' ': LCD_P6x8Str(1,1," ");
if(Data0<50)Data0+=5; Freq[0]=(20-Data0/5)/10+'0';
Freq[1]=(20-Data0/5)%10+'0';
LCD_P6x8Str(7,6*13,Freq);
break;
}
ee=num;
}
//*************************************
12864
//*************************************
//*************************************
//写数据地址
//*************************************
void write_12864com(uint8_t com)
{
uint8_t temp = 0x01;
uint8_t k[8] = {0};
uint8_t i;
Check_status();
for(i=0; i<8; i++)
{
if(com & temp)
k[i] = 1;
else
k[i] = 0;
temp=temp << 1;
}
temp = 0x01;
RS=0;
RW=0;
D0=k[0];
D1=k[1];
D2=k[2];
D3=k[3];
D4=k[4];
D5=k[5];
D6=k[6];
D7=k[7];
En=1;
Delay_Ms(1);
En=0;
Delay_Ms(1);
}
//*************************************
//写数据
//*************************************
void write_12864data(uint8_t dat)
{
uint8_t temp = 0x01;
uint8_t k[8] = {0};
uint8_t i;
Check_status();//延时检查很重要,在连续刷新的时候
for(i=0; i<8; i++)
{
if(dat & temp)
k[i] = 1;
else
k[i] = 0;
temp=temp << 1;
}
temp = 0x01;
RS=1;
RW=0;
D0=k[0];
D1=k[1];
D2=k[2];
D3=k[3];
D4=k[4];
D5=k[5];
D6=k[6];
D7=k[7];
En=1;//在使能信号的下降沿写入了数据
Delay_Ms(1);
En=0;
Delay_Ms(1);
}
uint8_t read_12864data()
{
//这个函数的代码测试未通过
uint8_t temp = 0;
uint8_t k[8] = {0};
uint8_t i;
Check_status();
RS=1;
RW=1;
En=1;//使能端高电平读取数据
Delay_Ms(1);
LCD12864_DataRead_PortInit();//端口方向改为输入
k[0]=DI0;
k[1]=DI1;
k[2]=DI2;
k[3]=DI3;
k[4]=DI4;
k[5]=DI5;
k[6]=DI6;
k[7]=DI7;
LCD12864_DataWrite_PortInit();//端口方向改为输出
for (i=0; i<8; i++)
{
temp |= ((k[i]&0x01)<
}
return temp;
}
void LCD_Set_Pos(uint8_t page,uint8_t x)//LCD当前光标设置,先选页,后选横向起始坐标
{
uint8_t Column=0;
(x>127)?(x=127):(x=x);
(x<1)?(x=0):(x=x);
if (page>8)
{
page=8;
}
else if (page<1)
{
page=1;
}
page=page-1;
if (x<=63)
{ LCDSelectScreen(LeftScreen);
LCDSetPage(page);
Column=x;
LCDSetColumn(Column);
}
else if (x>63)
{ LCDSelectScreen(RightScreen);
LCDSetPage(page);
Column = x-64;
LCDSetColumn(Column);
// if (Column == 0)
// { //如果第一次进入右半屏,需要空写一次,在设置一次,方可
// write_12864data(0x00);
// }
LCDSelectScreen(RightScreen);//上面的判断不对,应该是写两次命令就会解决右半屏首字下沉那个问题
LCDSetPage(page);
Column = x-64;
LCDSetColumn(Column);
}
}
void LCD_P6x8Str(uint8_t x, uint8_t y, char ch[])
{
uint8_t c = 0, i = 0, j = 0;
while (ch[j] != '�')
{
c = ch[j]-32;
for (i = 0; i < 6; i++)
{ LCD_Set_Pos(x, y);//因为这个AMPIRE 分为左右半屏,所以光标设置必须写在这里,确保每个字符是完整的
write_12864data(F6x8[c][i]);
y = y+1;
}
j++;
}
}
void LCD_DispACat(unsigned char x, unsigned char y)
{
unsigned char i = 0, j = 0;
if (x > 4)
{
x = 4;
y++;
}
x=x-1;
for (j = 0; j < 4; j++)
{
LCD_Set_Pos(x, y);
x++;
for (i = 0; i < 32; i++)
write_12864data(LCD_cat[i + j * 32]);
}
}
//********************************************************
//12864初始化
//********************************************************
void Init_12864()
{
//端口初始化
RCC->APB2ENR|=1<<2; //使能PORTA时钟
GPIOA->CRH&=0X00000000;
GPIOA->CRH|=0X44333333;//PA8~13推挽输出,PA14,15浮空输入,因为这个型号的LCD要检测内部是否忙
GPIOA->ODR|=0X00FFFFFF;//PA8~13输出高
LCD12864_DataWrite_PortInit();
Reset=0;
Delay_Ms(1);
Reset=1;
Check_status();
LCDSelectScreen(AllScreen);//屏幕选择全屏
LCDSetOnOff(Off);
LCDSelectScreen(AllScreen);//屏幕选择全屏
LCDSetOnOff(On);
LCDSelectScreen(AllScreen);//屏幕选择全屏
LCDClearScreen(AllScreen);//清屏
LCDSetLine(0);
}
void LCD12864_DataWrite_PortInit()
{
RCC->APB2ENR|=1<<2;
GPIOA->CRL&=0X00000000; //PORTA低八位为数据位,推挽输出,写数据用
GPIOA->CRL|=0X33333333;
GPIOA->ODR|=0XFFFFFFFF;
}
void LCD12864_DataRead_PortInit()
{
RCC->APB2ENR|=1<<2;
GPIOA->CRL&=0X00000000; //PORTA低八位为数据位,浮空输入,读数据用
GPIOA->CRL|=0X44444444;
//GPIOA->ODR|=0XFFFFFFFF;
}
void LCDSelectScreen(ScreenTypedef screen)
{
switch(screen)
{
case AllScreen:
CS1=0;
CS2=0;
break;
case LeftScreen:
CS1=0;
CS2=1;
break;
case RightScreen:
CS1=1;
CS2=0;
break;
default :
break;
}
}
void LCDSetOnOff(LCDSetOnOffTypedef Status)
{
switch (Status)
{
case On:
write_12864com(0x3e+1);
break;
case Off:
write_12864com(0x3e);
break;
default:
break;
}
}
void LCDClearScreen(ScreenTypedef screen)
{
uint8_t i,j;
LCDSelectScreen(screen);
for (i=0; i<=7; i++)
{
LCDSetPage(i);
LCDSetColumn(0);
for(j=0; j<=63; j++)
{
write_12864data(0x00);//写完后地址自动加一
}
}
}
void LCDSetPage(uint8_t Page)
{
Page=0xb8|Page;
write_12864com(Page);
}
void LCDSetLine(uint8_t Line)
{
Line=0xc0|Line;
write_12864com(Line);
}
void LCDSetColumn(uint8_t Colnum)
{
Colnum=Colnum&0x3f;
Colnum=Colnum|0x40;
write_12864com(Colnum);
}
void Check_status()
{
D0=0;
D1=0;
D2=0;
D3=0;
D4=0;
D5=0;
D6=0;
D7=0;
RS=0;
RW=1;
//En=1;
// while(CheckPin == 0);//不启用忙检测
Delay_Ms(2);
//En=0;
}
-
正弦波
+关注
关注
11文章
635浏览量
55250 -
STM32
+关注
关注
2265文章
10870浏览量
354692 -
信号发生器
+关注
关注
28文章
1452浏览量
108643 -
波形发生器
+关注
关注
3文章
288浏览量
31352
发布评论请先 登录
相关推荐
评论