題目來(lái)源于某雙流一大學(xué)第八屆“電協(xié)杯”電子設(shè)計(jì)(校賽)
大一C組:自定義信號(hào)發(fā)生器
隊(duì)伍名稱:擺爛三人組
下文有對(duì)相應(yīng)軟件和硬件的實(shí)現(xiàn)進(jìn)行介紹


復(fù)盤電賽(軟件部分)
讀題方面
定時(shí)的基礎(chǔ)單位是1ms?。?!
模式二中自定義輸出波,不僅僅是控制每個(gè)波在周期的輸出占比(時(shí)間),還要能夠定義三個(gè)波的輸出順序(不一定是先輸出正弦,后方波,最后三角波)。
不是通過(guò)單片機(jī)輸出波形。
應(yīng)當(dāng)軟件項(xiàng)目開(kāi)發(fā)前應(yīng)當(dāng)畫好結(jié)構(gòu)流程圖(狀態(tài)機(jī))再根據(jù)狀態(tài)機(jī)線路流程依次封裝相應(yīng)的功能,使邏輯顯得更加清晰、縝密,同時(shí)開(kāi)發(fā)效率也會(huì)大為提高
整個(gè)電賽過(guò)程吸取的教訓(xùn)
【反思】在這次的軟件開(kāi)發(fā)中,因?yàn)樵诔跗跊](méi)有規(guī)劃好完整的流程圖,主函數(shù)中的一些代碼存在冗余的情況,并且前期開(kāi)發(fā)邏輯混亂,一直在修改代碼邏輯,導(dǎo)致浪費(fèi)了很多時(shí)間】
【本次電賽未提前規(guī)劃流程圖造成的不便】在電賽驗(yàn)收的前一天晚上才發(fā)現(xiàn)一個(gè)非常容易忽略的說(shuō)明:“定時(shí)時(shí)間的基本單位為1ms”。雖然在定時(shí)器0的模塊中只需要把對(duì)應(yīng)的參數(shù)由1000ms改為1ms即可實(shí)現(xiàn)單位重置,但是前面許多LCD顯示的內(nèi)容都需要要重新編寫,因?yàn)?span id="n5n3t3z" class="kdocs-color" style="background-color:#FBF5B3;">這些顯示內(nèi)容并沒(méi)有做整合封裝,很不便于修改!!當(dāng)時(shí)為了程序的穩(wěn)定運(yùn)行沒(méi)有對(duì)此處做更改,讓整個(gè)軟件在電賽中沒(méi)有起到得拓展分的作用
軟件部分
實(shí)現(xiàn)原理:編寫51單片機(jī)狀態(tài)機(jī),通過(guò)定時(shí)器0來(lái)控制三個(gè)外接引腳(P2^0-P2^2)的高低電平的時(shí)間以達(dá)到自定義輸出波的目的
WARMING
聲明在前:
軟件中的LCD顯示還未改動(dòng),還缺少在模式二下輸出順序可選的狀態(tài)機(jī)模塊,該代碼僅作為思路指引,沒(méi)有做到完全正確!?。?/span>
main.c代碼仍然存在多出紕漏亟待修改,請(qǐng)多包含(題主正忙于學(xué)習(xí)stm32,還沒(méi)有時(shí)間來(lái)修正代碼,如果這篇文章閱讀量大于500,請(qǐng)?jiān)谠u(píng)論區(qū)踢題主一腳)
使用到的外設(shè):LCD1602顯示屏
注意事項(xiàng):
八位數(shù)據(jù)線依次接入外部引腳P1^0-P1^7
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7
LCD1602.c
#include <REG52.H>
//引腳配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P1
//函數(shù)定義:
/**
* @brief LCD1602延時(shí)函數(shù),12MHz調(diào)用可延時(shí)1ms
* @param 無(wú)
* @retval 無(wú)
*/
void LCD_Delay()
{
unsigned char i, j;
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
/**
* @brief LCD1602寫命令
* @param Command 要寫入的命令
* @retval 無(wú)
*/
void LCD_WriteCommand(unsigned char Command)
{
LCD_RS=0;
LCD_RW=0;
LCD_DataPort=Command;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}
/**
* @brief LCD1602寫數(shù)據(jù)
* @param Data 要寫入的數(shù)據(jù)
* @retval 無(wú)
*/
void LCD_WriteData(unsigned char Data)
{
LCD_RS=1;
LCD_RW=0;
LCD_DataPort=Data;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}
/**
* @brief LCD1602設(shè)置光標(biāo)位置
* @param Line 行位置,范圍:1~2
* @param Column 列位置,范圍:1~16
* @retval 無(wú)
*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
if(Line==1)
{
LCD_WriteCommand(0x80|(Column-1));
}
else if(Line==2)
{
LCD_WriteCommand(0x80|(Column-1+0x40));
}
}
/**
* @brief LCD1602初始化函數(shù)
* @param 無(wú)
* @retval 無(wú)
*/
void LCD_Init()
{
LCD_WriteCommand(0x38);//八位數(shù)據(jù)接口,兩行顯示,5*7點(diǎn)陣
LCD_WriteCommand(0x0c);//顯示開(kāi),光標(biāo)關(guān),閃爍關(guān)
LCD_WriteCommand(0x06);//數(shù)據(jù)讀寫操作后,光標(biāo)自動(dòng)加一,畫面不動(dòng)
LCD_WriteCommand(0x01);//光標(biāo)復(fù)位,清屏
}
/**
* @brief 在LCD1602指定位置上顯示一個(gè)字符
* @param Line 行位置,范圍:1~2
* @param Column 列位置,范圍:1~16
* @param Char 要顯示的字符
* @retval 無(wú)
*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
LCD_SetCursor(Line,Column);
LCD_WriteData(Char);
}
/**
* @brief 在LCD1602指定位置開(kāi)始顯示所給字符串
* @param Line 起始行位置,范圍:1~2
* @param Column 起始列位置,范圍:1~16
* @param String 要顯示的字符串
* @retval 無(wú)
*/
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=0;String[i]!='\0';i++)
{
LCD_WriteData(String[i]);
}
}
/**
* @brief 返回值=X的Y次方
*/
int LCD_Pow(int X,int Y)
{
unsigned char i;
int Result=1;
for(i=0;i<Y;i++)
{
Result*=X;
}
return Result;
}
/**
* @brief 在LCD1602指定位置開(kāi)始顯示所給數(shù)字
* @param Line 起始行位置,范圍:1~2
* @param Column 起始列位置,范圍:1~16
* @param Number 要顯示的數(shù)字,范圍:0~65535
* @param Length 要顯示數(shù)字的長(zhǎng)度,范圍:1~5
* @retval 無(wú)
*/
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
}
}
/**
* @brief 在LCD1602指定位置開(kāi)始以有符號(hào)十進(jìn)制顯示所給數(shù)字
* @param Line 起始行位置,范圍:1~2
* @param Column 起始列位置,范圍:1~16
* @param Number 要顯示的數(shù)字,范圍:-32768~32767
* @param Length 要顯示數(shù)字的長(zhǎng)度,范圍:1~5
* @retval 無(wú)
*/
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
unsigned char i;
unsigned int Number1;
LCD_SetCursor(Line,Column);
if(Number>=0)
{
LCD_WriteData('+');
Number1=Number;
}
else
{
LCD_WriteData('-');
Number1=-Number;
}
for(i=Length;i>0;i--)
{
LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
}
}
/**
* @brief 在LCD1602指定位置開(kāi)始以十六進(jìn)制顯示所給數(shù)字
* @param Line 起始行位置,范圍:1~2
* @param Column 起始列位置,范圍:1~16
* @param Number 要顯示的數(shù)字,范圍:0~0xFFFF
* @param Length 要顯示數(shù)字的長(zhǎng)度,范圍:1~4
* @retval 無(wú)
*/
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i,SingleNumber;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
SingleNumber=Number/LCD_Pow(16,i-1)%16;
if(SingleNumber<10)
{
LCD_WriteData(SingleNumber+'0');
}
else
{
LCD_WriteData(SingleNumber-10+'A');
}
}
}
/**
* @brief 在LCD1602指定位置開(kāi)始以二進(jìn)制顯示所給數(shù)字
* @param Line 起始行位置,范圍:1~2
* @param Column 起始列位置,范圍:1~16
* @param Number 要顯示的數(shù)字,范圍:0~1111 1111 1111 1111
* @param Length 要顯示數(shù)字的長(zhǎng)度,范圍:1~16
* @retval 無(wú)
*/
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
}
}
LCD1602.h
#ifndef __LCD1602_H__
#define __LCD1602_H__
//用戶調(diào)用函數(shù):
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
#endif
同時(shí)使用到了定時(shí)器0
Timer0.c
#include <REGX52.H>
/**
* @brief 定時(shí)器0初始化,1毫秒@12.000MHz
* @param 無(wú)
* @retval 無(wú)
*/
void Timer0_Init(void)
{
TMOD &= 0xF0; //設(shè)置定時(shí)器模式
TMOD |= 0x01; //設(shè)置定時(shí)器模式
TL0 = 0x18; //設(shè)置定時(shí)初值
TH0 = 0xFC; //設(shè)置定時(shí)初值
TF0 = 0; //清除TF0標(biāo)志
TR0 = 1; //定時(shí)器0開(kāi)始計(jì)時(shí)
ET0=1;
EA=1;
PT0=0;
}
Timer0.h
#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0_Init(void);
#endif
以及用于矩陣鍵盤的軟件消抖Delay
Delay.c
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
Delay.h
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int xms);
#endif
主函數(shù)控制管腳高低電平輸出
軟件控制流程圖

main.c封裝代碼框架
//矩陣鍵盤-鍵值判斷
uchar MatrixKey();
//輸出電平模塊
void Main_Otp();//控制輸出引腳
void Out_Ctl_P0(uchar opt);//控制輸出
//模式判斷-狀態(tài)機(jī)
uint OverFLoat(uint num);//防止數(shù)據(jù)溢出:將修改時(shí)間的范圍控制在0-9s
void Mod_Single();//模式一單波的輸出與停止
void Mod_Multi();//模式二三波混合輸出
//狀態(tài)機(jī)-主控系統(tǒng)
void Main_Ctl(); //統(tǒng)帥整個(gè)狀態(tài)機(jī)的狀態(tài)判斷(由按鍵決定狀態(tài)的走向)
void Init_System();//初始化整個(gè)系統(tǒng)
Main_Ctl()判斷處于那個(gè)模式下,將工作分配給 Mod_Single()與Mod_Multi()
Mod_Single()與Mod_Multi()都會(huì)在調(diào)節(jié)時(shí)間的時(shí)候去調(diào)用防溢出函數(shù)OverFLoat
主函數(shù)main會(huì)調(diào)用一個(gè)【(按鍵)狀態(tài)機(jī)判斷模塊】Main_Ctl()與
【引腳高低電平輸出的模塊】Main_Otp()
將模式一、二的相關(guān)時(shí)間,鍵值,狀態(tài)等參數(shù)均封裝在sta這個(gè)結(jié)構(gòu)體供全局是使用
相應(yīng)參數(shù)介紹:
外部引腳P2^0-P2^2:分別對(duì)應(yīng)繼電器的三個(gè)開(kāi)關(guān),在通過(guò)這三個(gè)開(kāi)關(guān)分別連接到三個(gè)波的電路上
flag_singleOK是模式一中完成
flag_allOK是模式二中完成三個(gè)波的各自輸出時(shí)間
main.c
/**
* @file main.c
* @author jUicE_g2R(qq:3406291309)
*
* @brief 通過(guò)按鍵狀態(tài)機(jī)實(shí)現(xiàn)兩個(gè)模式下三個(gè)外接引腳的高低電平輸出
* @用途:控制C組中三種不同波形的輸出
*
* @version 0.1
* 0.1:通過(guò)按鍵控制狀態(tài)機(jī)輸出電平
* 0.2:PC端通過(guò)UART串口通信控制狀態(tài)機(jī)輸出電平
*
* @date 2023-3-6(the Latest Correct Time)
*
* @code(state) 已完成兩種模式的調(diào)試
*
* @copyright Copyright (c) 2023
*/
#include <REG52.H>
#include "Timer0.h"
#include "Delay.h"
#include "LCD1602.h"
#define uint unsigned int
#define uchar unsigned char
sbit opt1=P2^0; //小燈測(cè)試演示波輸出
sbit opt2=P2^1;
sbit opt3=P2^2;
#define Keys P3 //矩陣鍵盤總控鍵
//記錄波形輸入
struct state
{
//值Val
uchar wave_val; //波值
uchar key_val; //矩陣鍵盤鍵值
//控制狀態(tài)
uchar flag_singleOK;
uchar flag_otp; //是否輸出波
uchar flag_free; //是否進(jìn)入自由模式
uchar flag_allOK; //確定
//模式一----輸出時(shí)間與停止時(shí)間
uint wave_otp_t;
uint wave_stop_t;
//模式二----各波輸出的時(shí)間0-9
uint wave_t1;
uint wave_t2;
uint wave_t3;
//輸出判斷flag聲明
uchar flag1_process;
uchar flag2_process;
} sta={1,0,0,1,0,0,1,1,1,1,1,0,0};
/*-----------子函數(shù)聲明------------*/
//矩陣鍵盤-鍵值判斷
uchar MatrixKey();
//輸出電平模塊
void Main_Otp();
void Out_Ctl_P0(uchar opt);
//模式判斷-狀態(tài)機(jī)
uint OverFLoat(uint num);
void Mod_Single();
void Mod_Multi();
//狀態(tài)機(jī)-主控系統(tǒng)
void Main_Ctl();
void Init_System();
//主函數(shù)
int main(void)
{
Init_System();
while(1)
{
Main_Otp();
Main_Ctl();
}
}
uchar hex[5]={0,0xE,0xD,0xB,0x7};
/*-------------矩陣鍵盤 檢測(cè)算法------------*/
uchar MatrixKey()
{
uchar row, colu, value, value_temp, i;
uchar rank; //矩陣鍵盤鍵號(hào)
Keys=0x0f;//矩陣鍵盤初始化
if(Keys!=0x0f)
{
Delay(10);//軟件消抖
if(Keys!=0x0f)
{
row=Keys;
Keys=0xf0;
colu=Keys;
value=row+colu;
rank=0;
value_temp=value%16;
for( i=1;i<=4;i++)
{
if(value_temp==hex[i])
rank=(i-1)*4;
}
value_temp=value/16;
for( i=1;i<=4;i++)
{
if(value_temp==hex[i])
rank+=i;
}
while(Keys==0xFF);
}
while(Keys!=0xf0);
}
else
{
rank=0;
}
return rank;
}
/*------------電平輸出控制-----------*/
void Out_Ctl_P0(uchar opt)
{
switch (opt)
{
case 0:
opt1=0;
opt2=0;
opt3=0;
case 1:
opt1=1;
opt2=0;
opt3=0;
break;
case 2:
opt1=0;
opt2=1;
opt3=0;
break;
case 3:
opt1=0;
opt2=0;
opt3=1;
default:
break;
}
}
void Main_Otp() //引腳輸出
{
if(sta.flag_singleOK==1)
{
switch (sta.flag1_process)
{
case 1: //輸出
Out_Ctl_P0(sta.wave_val);
break;
case 2: //停止
opt1=0;
opt2=0;
opt3=0;
break;
default:
break;
}
}
if(sta.flag_allOK==1)
{
switch (sta.flag2_process)
{
case 1: //輸出一號(hào)波
opt1=1;
opt2=0;
opt3=0;
break;
case 2: //輸出二號(hào)波
opt1=0;
opt2=1;
opt3=0;
break;
case 3: //輸出三號(hào)波
opt1=0;
opt2=0;
opt3=1;
break;
default:
break;
}
}
if(sta.flag_otp==0)
{
LCD_ShowString(1,4,"STOP");
}
}
uint OverFLoat(uint num)
{
if(num>9)
{
num=0;
}
else if(num<0)
{
num=9;
}
return num;
}
/*-----------------鍵值處理-----------------*/
void Mod_Single() //單項(xiàng)調(diào)試
{
static uchar wave_temp=1;
static uchar flag_OKTemp=0;
static uchar i=1;
uchar wave_t;
if(sta.key_val==4&i==3) //選定波,輸出以及停止時(shí)間后輸出
{
i=1; //重置
sta.flag_singleOK=1;
LCD_ShowString(1,12,"allOK");
LCD_ShowString(1,4,"OPT_");
}
else
{
switch (sta.key_val)
{
case 1:
wave_temp++;
if(wave_temp>3)
{
wave_temp=1;
}
LCD_ShowNum(1,2,wave_temp,1);//顯示波號(hào)
sta.wave_val=wave_temp; //記錄wave號(hào):便于停止波后重啟時(shí)波保持停止前的輸出狀態(tài)
break;
case 2: //是否輸出波
sta.flag_otp++;
if((sta.flag_otp)>1)
{
sta.flag_otp=0;
}
if(sta.flag_otp==0) //停止輸出波
{
sta.flag_singleOK=0;
}
break;
case 4:
i++;
flag_OKTemp=1;
break;
case 6: //輸出時(shí)間
flag_OKTemp=0;
switch (i)
{
case 2:
wave_t=sta.wave_otp_t+1;
sta.wave_otp_t=OverFLoat(wave_t);
LCD_ShowNum(1,9,sta.wave_otp_t,1);
break;
case 3:
wave_t=sta.wave_stop_t+1;
sta.wave_stop_t=OverFLoat(wave_t);
LCD_ShowNum(1,11,sta.wave_stop_t,1);
break;
default:
break;
}
break;
case 7: //停止時(shí)間
flag_OKTemp=0;
switch (i)
{
case 2:
wave_t=sta.wave_otp_t-1;
sta.wave_otp_t=OverFLoat(wave_t);
LCD_ShowNum(1,9,sta.wave_otp_t,1);
break;
case 3:
wave_t=sta.wave_stop_t-1;
sta.wave_stop_t=OverFLoat(wave_t);
LCD_ShowNum(1,11,sta.wave_stop_t,1);
break;
default:
break;
}
break;
default:
break;
}
if(flag_OKTemp==0)
{
LCD_ShowString(1,15,"no");
}
else
{
LCD_ShowString(1,15,"OK");
}
}
}
void Mod_Multi() //自由模式
{
static uchar flag_OKTemp=0;
uint wave_t;
static uchar i=0; //調(diào)好三個(gè)波的時(shí)間就可以輸出了
if(i==3&&sta.key_val==4) //切換到第三個(gè)波且確定時(shí),開(kāi)始輸出波
{
i=1; //重置
sta.flag_allOK=1; //可以輸出波了
sta.flag_otp=1; //引腳高電平輸出
LCD_ShowString(1,12,"allOK");
LCD_ShowString(1,4,"OPT_");
}
else //選擇波以及波輸出時(shí)間
{
switch (sta.key_val)
{
case 4: //每個(gè)波形時(shí)間確定鍵
flag_OKTemp=1;
i++;
break;
case 5: //切波:在確定的條件下才能切波
if(flag_OKTemp==1)
{
sta.wave_val++;
if(sta.wave_val>3)
{
sta.wave_val=1;
}
flag_OKTemp=0; //重置OK值
LCD_ShowNum(1,2,sta.wave_val,1); //切換的波的波號(hào)顯示
}
break;
case 6: //增加波的時(shí)間
flag_OKTemp=0;
switch (sta.wave_val)
{
case 1:
wave_t=sta.wave_t1+1;
sta.wave_t1=OverFLoat(wave_t);
LCD_ShowNum(2,4,sta.wave_t1,1);
break;
case 2:
wave_t=sta.wave_t2+1;
sta.wave_t2=OverFLoat(wave_t);
LCD_ShowNum(2,9,sta.wave_t2,1);
break;
case 3:
wave_t=sta.wave_t3+1;
sta.wave_t3=OverFLoat(wave_t);
LCD_ShowNum(2,14,sta.wave_t3,1);
break;
default:
break;
}
break;
case 7: //減少波的時(shí)間
flag_OKTemp=0;
switch (sta.wave_val)
{
case 1:
wave_t=sta.wave_t1-1;
sta.wave_t1=OverFLoat(wave_t);
LCD_ShowNum(2,4,sta.wave_t1,1);
break;
case 2:
wave_t=sta.wave_t2-1;
sta.wave_t2=OverFLoat(wave_t);
LCD_ShowNum(2,9,sta.wave_t2,1);
break;
case 3:
wave_t=sta.wave_t3-1;
sta.wave_t3=OverFLoat(wave_t);
LCD_ShowNum(2,14,sta.wave_t3,1);
break;
default:
break;
}
break;
default:
break;
}
if(flag_OKTemp==0)
{
LCD_ShowString(1,15,"no");
}
else
{
LCD_ShowString(1,15,"OK");
}
}
}
void Main_Ctl() //主控模塊
{
uchar wave_temp=1;
sta.key_val=MatrixKey(); //獲取矩陣鍵值
if(sta.key_val!=0) //沒(méi)有鍵按下就不進(jìn)入判斷
{
if(sta.flag_free==1)
{
if(sta.key_val==2) //在自由模式下任何情況都可以退出
{
sta.flag_otp=0; //停止輸出波
sta.flag_free=0; //退出自由調(diào)節(jié)模式
LCD_ShowChar(2,16,'S'); //還原到單項(xiàng)操作
LCD_ShowString(1,15,"no");
}
else
{
Mod_Multi();
}
}
else if(sta.flag_free==0) //單項(xiàng)輸出波
{
LCD_ShowChar(2,16,'S'); //更改模式
if(sta.flag_otp==0) //進(jìn)入停止輸出才能調(diào)至自由調(diào)整模式
{
if(sta.key_val==3) //進(jìn)入自由調(diào)整模式
{
sta.flag_free=1; //此時(shí)波形已經(jīng)停止輸出
LCD_ShowChar(2,16,'M'); //更改模式
LCD_ShowString(1,4,"STOP");
LCD_ShowString(1,8," ");
Timer0_Init(); //重置定時(shí)器0
//輸出初始化
opt1=0;
opt2=0;
opt3=0;
}
}
else if(sta.flag_otp==1) //輸出波
{
Mod_Single();
}
}
}
}
void Init_System() //初始化系統(tǒng)
{
Timer0_Init(); //定時(shí)器初始化
/*屏幕初始化*/
LCD_Init();
//第一行演示: |W1 S|
LCD_ShowChar(1,1,'W'); //表示所處的波形
LCD_ShowNum(1,2,1,1); //波號(hào)
LCD_ShowString(1,4,"STOP");
LCD_ShowChar(2,16,'S'); //模式
//第二行演示: |W1 1 W2 2 W3 3 no|
LCD_ShowChar(2,1,'W');
LCD_ShowNum(2,2,1,1);
LCD_ShowChar(2,3,':');
LCD_ShowChar(2,6,'W');
LCD_ShowNum(2,7,2,1);
LCD_ShowChar(2,8,':');
LCD_ShowChar(2,11,'W');
LCD_ShowNum(2,12,3,1);
LCD_ShowChar(2,13,':');
LCD_ShowString(1,15,"no");
LCD_ShowChar(1,10,'|');
/*引腳輸出輸出初始化*/
// Out_Ctl_P0(0); //初始化輸出端口
opt1=0;
opt2=0;
opt3=0;
}
/*定時(shí)器中斷函數(shù)*/
void Timer0_Routine() interrupt 1
{
static int T0cot1=0;
static int T0cot2=0;
TL0 = 0x18; //設(shè)置定時(shí)初值
TH0 = 0xFC; //設(shè)置定時(shí)初值
if(sta.flag_otp==1) //控制停止輸出波
{
//控制輸出波flag
if(sta.flag_singleOK==1)
{
if(T0cot1==0)
{
sta.flag1_process=1;
}
else if(T0cot1==1*sta.wave_otp_t)
{
sta.flag1_process=2;
}
T0cot1++;
//重置循化
if(T0cot1>1*(sta.wave_otp_t+sta.wave_stop_t))
{
T0cot1=0;
}
}
if(sta.flag_allOK==1)
{
//控制輸出波flag
if (T0cot2==0)
{
sta.flag2_process=1;
}
else if(T0cot2==1*sta.wave_t1)
{
sta.flag2_process=2;
}
else if(T0cot2==1*(sta.wave_t1+sta.wave_t2))
{
sta.flag2_process=3;
}
T0cot2++;
if(T0cot2>1*(sta.wave_t1+sta.wave_t2+sta.wave_t3)) //重置,循環(huán)
{
T0cot2=0;
}
}
}
}
硬件部分
波形產(chǎn)生分析
正弦波發(fā)生電路
采用文式橋振蕩電路為基礎(chǔ)產(chǎn)生正弦波,組成為:放大電路、反饋網(wǎng)絡(luò)、選頻網(wǎng)絡(luò)、穩(wěn)幅環(huán)節(jié)
放大電路:
文氏電橋振蕩器采用的是同相放大器,當(dāng)信號(hào)較小時(shí),二極管不導(dǎo)通,放大倍數(shù)為A=1+(RP2+R1)/R8
當(dāng)信號(hào)較大時(shí),二極管導(dǎo)通,放大倍數(shù)為A=1+(RP2+r)/R8,r為R1所對(duì)應(yīng)的匹配電阻。
反饋網(wǎng)絡(luò):
反饋是將輸出信號(hào)的全部或一部分返回至輸入,使輸入信號(hào)改變,而負(fù)反饋是引起輸入信號(hào)減小的一種反饋方式。同向放大器引入負(fù)反饋,使得輸出信號(hào)與輸入信號(hào)比值穩(wěn)定。
選頻網(wǎng)路:
RC帶通濾波器,該電路由高通和低通濾波器組合而成,其中RP1=RP4,C1=C2,頻率為f=1/(2πRC)。
f=1/(2*Π*RC)(RP1 = RP4,C1 = C2),f=1/(2*Π*RP1*C2)。
穩(wěn)幅環(huán)節(jié):
文氏電橋的起振條件是:|AF|>1;但文氏電橋的穩(wěn)幅條件確是:|AF|=1。利用二極管的非線性自動(dòng)調(diào)節(jié)負(fù)反饋的強(qiáng)弱來(lái)控制輸出電壓的恒定。振蕩過(guò)程中D1、D2將交替導(dǎo)通和截止,總有一個(gè)處于正向?qū)顟B(tài)的二極管與R3并聯(lián),由于二極管正向電阻rd隨ud增大而下降,因此負(fù)反饋隨振幅上升而增強(qiáng),也就是說(shuō)A隨振幅增大而下降,直到滿足振幅平衡條件為止。
圖中RP1和RP4可調(diào)節(jié)頻率,RP2可調(diào)節(jié)放大倍數(shù)。
方波發(fā)生電路
利用下行滯回比較器輸出方波,滯回比較器的輸入電壓逐漸增大或者減小時(shí),有兩個(gè)不相等的閾值,其傳輸特性具有滯回曲線的形狀,因此具有很強(qiáng)的抗干擾能力。
uo=土Uz,
RP3調(diào)節(jié)放大倍數(shù)。

三角波發(fā)生電路
利用集成運(yùn)放構(gòu)成積分器,然后對(duì)方波信號(hào)進(jìn)行運(yùn)算產(chǎn)生三角波。
R7是防止積分電路飽和的反饋電阻,它的大小需要比R1大兩個(gè)數(shù)量級(jí),這樣就不會(huì)影響積分波形,R7越大三角波越往上。RP3和R5與E1的值決定三角波斜率,因此調(diào)節(jié)RP3可以改變?nèi)遣ǖ姆怠?mark hidden color="red">文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-756471.html

軟件與硬件橋接——電路開(kāi)關(guān)設(shè)計(jì)
用繼電器模塊作為開(kāi)關(guān),對(duì)電路三種輸出波形進(jìn)行控制。由于繼電器模塊觸發(fā)電壓為3.3V~5V,進(jìn)而可用控制單片機(jī)引腳輸出的高低電平的方法來(lái)控制繼電器的開(kāi)關(guān),從而實(shí)現(xiàn)對(duì)輸出波形的智能化控制文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-756471.html
三位一體原理圖

到了這里,關(guān)于大一電賽:51單片機(jī)(狀態(tài)機(jī)編程)——控制外部開(kāi)關(guān)(繼電器)達(dá)到自定義輸出波的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!