大一电赛:51单片机(状态机编程)——控制外部开关(继电器)达到自定义输出波

这篇具有很好参考价值的文章主要介绍了大一电赛:51单片机(状态机编程)——控制外部开关(继电器)达到自定义输出波。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

题目来源于某双流一大学第八届“电协杯”电子设计(校赛)

大一C组:自定义信号发生器

队伍名称:摆烂三人组

下文有对相应软件和硬件的实现进行介绍

电子设计大赛编程,51单片机,电赛,嵌入式,51单片机,单片机,嵌入式硬件,硬件工程,Powered by 金山文档
电子设计大赛编程,51单片机,电赛,嵌入式,51单片机,单片机,嵌入式硬件,硬件工程,Powered by 金山文档

复盘电赛(软件部分)

读题方面

  • 定时的基础单位是1ms!!!

  • 模式二中自定义输出波,不仅仅是控制每个波在周期的输出占比(时间),还要能够定义三个波的输出顺序(不一定是先输出正弦,后方波,最后三角波)。

  • 不是通过单片机输出波形。

  • 应当软件项目开发前应当画好结构流程图(状态机)再根据状态机线路流程依次封装相应的功能,使逻辑显得更加清晰、缜密,同时开发效率也会大为提高

整个电赛过程吸取的教训

【反思】在这次的软件开发中,因为在初期没有规划好完整的流程图,主函数中的一些代码存在冗余的情况,并且前期开发逻辑混乱,一直在修改代码逻辑,导致浪费了很多时间】

【本次电赛未提前规划流程图造成的不便】在电赛验收的前一天晚上才发现一个非常容易忽略的说明:“定时时间的基本单位为1ms”。虽然在定时器0的模块中只需要把对应的参数由1000ms改为1ms即可实现单位重置,但是前面许多LCD显示的内容都需要要重新编写,因为这些显示内容并没有做整合封装,很不便于修改!!当时为了程序的稳定运行没有对此处做更改,让整个软件在电赛中没有起到得拓展分的作用

软件部分

实现原理:编写51单片机状态机,通过定时器0来控制三个外接引脚(P2^0-P2^2)的高低电平的时间以达到自定义输出波的目的

WARMING

声明在前:

软件中的LCD显示还未改动,还缺少在模式二下输出顺序可选的状态机模块,该代码仅作为思路指引,没有做到完全正确!!!

main.c代码仍然存在多出纰漏亟待修改,请多包含(题主正忙于学习stm32,还没有时间来修正代码,如果这篇文章阅读量大于500,请在评论区踢题主一脚)

  • 使用到的外设:LCD1602显示屏

注意事项:

八位数据线依次接入外部引脚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

//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
    unsigned char i, j;

    i = 2;
    j = 239;
    do
    {
        while (--j);
    } while (--i);
}

/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
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写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
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设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
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初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()
{
    LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
    LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
    LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
    LCD_WriteCommand(0x01);//光标复位,清屏
}

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
    LCD_SetCursor(Line,Column);
    LCD_WriteData(Char);
}

/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
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指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
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指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
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指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
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指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
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__

//用户调用函数:
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
  • 同时使用到了定时器0

Timer0.c
#include <REGX52.H>

/**
  * @brief  定时器0初始化,1毫秒@12.000MHz
  * @param  无
  * @retval 无
  */
void Timer0_Init(void)
{
    TMOD &= 0xF0;        //设置定时器模式
    TMOD |= 0x01;        //设置定时器模式
    TL0 = 0x18;        //设置定时初值
    TH0 = 0xFC;        //设置定时初值
    TF0 = 0;        //清除TF0标志
    TR0 = 1;        //定时器0开始计时
    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

主函数控制管脚高低电平输出

软件控制流程图
电子设计大赛编程,51单片机,电赛,嵌入式,51单片机,单片机,嵌入式硬件,硬件工程,Powered by 金山文档
main.c封装代码框架

//矩阵键盘-键值判断

uchar MatrixKey();

//输出电平模块

void Main_Otp();//控制输出引脚

void Out_Ctl_P0(uchar opt);//控制输出

//模式判断-状态机

uint OverFLoat(uint num);//防止数据溢出:将修改时间的范围控制在0-9s

void Mod_Single();//模式一单波的输出与停止

void Mod_Multi();//模式二三波混合输出

//状态机-主控系统

void Main_Ctl(); //统帅整个状态机的状态判断(由按键决定状态的走向)

void Init_System();//初始化整个系统

  • Main_Ctl()判断处于那个模式下,将工作分配给 Mod_Single()与Mod_Multi()

  • Mod_Single()与Mod_Multi()都会在调节时间的时候去调用防溢出函数OverFLoat

  • 主函数main会调用一个【(按键)状态机判断模块】Main_Ctl()与

【引脚高低电平输出的模块】Main_Otp()

  • 将模式一、二的相关时间,键值,状态等参数均封装在sta这个结构体供全局是使用

相应参数介绍:

外部引脚P2^0-P2^2:分别对应继电器的三个开关,在通过这三个开关分别连接到三个波的电路上

flag_singleOK是模式一中完成

flag_allOK是模式二中完成三个波的各自输出时间

main.c
/**
 * @file main.c
 * @author jUicE_g2R(qq:3406291309)
 * 
 * @brief 通过按键状态机实现两个模式下三个外接引脚的高低电平输出
 * @用途:控制C组中三种不同波形的输出
 * 
 * @version 0.1
 *                     0.1:通过按键控制状态机输出电平
 *                     0.2:PC端通过UART串口通信控制状态机输出电平
 * 
 * @date 2023-3-6(the Latest Correct Time)
 * 
 * @code(state)     已完成两种模式的调试
 * 
 * @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;             //小灯测试演示波输出
sbit opt2=P2^1;
sbit opt3=P2^2;

#define Keys P3             //矩阵键盘总控键

//记录波形输入
struct state
{
    //值Val
    uchar wave_val;             //波值
    uchar key_val;          //矩阵键盘键值
    //控制状态
    uchar flag_singleOK;
    uchar flag_otp;           //是否输出波
    uchar flag_free;          //是否进入自由模式
    uchar flag_allOK;            //确定

    //模式一----输出时间与停止时间
    uint wave_otp_t;
    uint wave_stop_t;
    //模式二----各波输出的时间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};

/*-----------子函数声明------------*/
//矩阵键盘-键值判断
uchar MatrixKey();
//输出电平模块
void Main_Otp();
void Out_Ctl_P0(uchar opt);

//模式判断-状态机
uint OverFLoat(uint num);
void Mod_Single();
void Mod_Multi();
//状态机-主控系统
void Main_Ctl();
void Init_System();

//主函数
int main(void)
{
    Init_System();
    while(1)
    {
        Main_Otp();
        
        Main_Ctl();
    } 
}

uchar hex[5]={0,0xE,0xD,0xB,0x7};
/*-------------矩阵键盘      检测算法------------*/
uchar MatrixKey()
{
    uchar row, colu, value, value_temp, i;
    uchar rank;               //矩阵键盘键号

    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:         //输出一号波
                opt1=1;
                opt2=0;
                opt3=0;
                break;
            case 2:         //输出二号波
                opt1=0;
                opt2=1;
                opt3=0;
                break;
            case 3:         //输出三号波
                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()         //单项调试
{
    static uchar wave_temp=1;
    static uchar flag_OKTemp=0;
    static uchar i=1;
    uchar wave_t;

    if(sta.key_val==4&i==3)             //选定波,输出以及停止时间后输出
    {
        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);//显示波号
                sta.wave_val=wave_temp;      //记录wave号:便于停止波后重启时波保持停止前的输出状态
                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:     //输出时间
                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:     //停止时间
                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;           //调好三个波的时间就可以输出了

    if(i==3&&sta.key_val==4)       //切换到第三个波且确定时,开始输出波
    {
        i=1;        //重置
        sta.flag_allOK=1;       //可以输出波了
        sta.flag_otp=1;         //引脚高电平输出
        LCD_ShowString(1,12,"allOK");
        LCD_ShowString(1,4,"OPT_");
    }
    else        //选择波以及波输出时间
    {
        switch (sta.key_val)
        {
            case 4:     //每个波形时间确定键
                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);    //切换的波的波号显示
                }
                break;

            case 6:     //增加波的时间
                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:     //减少波的时间
                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)                  //没有键按下就不进入判断
    {
        if(sta.flag_free==1)
        {
            if(sta.key_val==2)             //在自由模式下任何情况都可以退出
            {
                sta.flag_otp=0;       //停止输出波
                sta.flag_free=0;      //退出自由调节模式
                LCD_ShowChar(2,16,'S');         //还原到单项操作
                LCD_ShowString(1,15,"no");
            }
            else
            {
                Mod_Multi();
            }
        }
        else if(sta.flag_free==0)          //单项输出波
        {
            LCD_ShowChar(2,16,'S');         //更改模式
            if(sta.flag_otp==0)            //进入停止输出才能调至自由调整模式
            {
                if(sta.key_val==3)         //进入自由调整模式
                {
                    sta.flag_free=1;       //此时波形已经停止输出 
                    LCD_ShowChar(2,16,'M');          //更改模式
                    LCD_ShowString(1,4,"STOP");
                    LCD_ShowString(1,8,"       ");
                    Timer0_Init();                   //重置定时器0
                    
                    //输出初始化
                    opt1=0;
                    opt2=0;
                    opt3=0;
                }
            }
            else if(sta.flag_otp==1)      //输出波
            {
                Mod_Single();
            }
        }
    } 
}

void Init_System()      //初始化系统
{
    Timer0_Init();      //定时器初始化
    /*屏幕初始化*/
    LCD_Init();

    //第一行演示:    |W1            S|
    LCD_ShowChar(1,1,'W');        //表示所处的波形
    LCD_ShowNum(1,2,1,1);         //波号
    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;
}

/*定时器中断函数*/
void Timer0_Routine() interrupt 1
{
    static int T0cot1=0;
    static int T0cot2=0;

    TL0 = 0x18;        //设置定时初值
    TH0 = 0xFC;        //设置定时初值
    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))        //重置,循环
            {
                T0cot2=0;
            }
        }
    }
}

硬件部分

  • 波形产生分析

正弦波发生电路

采用文式桥振荡电路为基础产生正弦波,组成为:放大电路、反馈网络、选频网络、稳幅环节

放大电路:

文氏电桥振荡器采用的是同相放大器,当信号较小时,二极管不导通,放大倍数为A=1+(RP2+R1)/R8

当信号较大时,二极管导通,放大倍数为A=1+(RP2+r)/R8,r为R1所对应的匹配电阻。

反馈网络:

反馈是将输出信号的全部或一部分返回至输入,使输入信号改变,而负反馈是引起输入信号减小的一种反馈方式。同向放大器引入负反馈,使得输出信号与输入信号比值稳定。

选频网路:

RC带通滤波器,该电路由高通和低通滤波器组合而成,其中RP1=RP4,C1=C2,频率为f=1/(2πRC)。

f=1/(2*Π*RC)(RP1 = RP4,C1 = C2),f=1/(2*Π*RP1*C2)。

稳幅环节:

文氏电桥的起振条件是:|AF|>1;但文氏电桥的稳幅条件确是:|AF|=1。利用二极管的非线性自动调节负反馈的强弱来控制输出电压的恒定。振荡过程中D1、D2将交替导通和截止,总有一个处于正向导通状态的二极管与R3并联,由于二极管正向电阻rd随ud增大而下降,因此负反馈随振幅上升而增强,也就是说A随振幅增大而下降,直到满足振幅平衡条件为止。

图中RP1和RP4可调节频率,RP2可调节放大倍数。

方波发生电路

利用下行滞回比较器输出方波,滞回比较器的输入电压逐渐增大或者减小时,有两个不相等的阈值,其传输特性具有滞回曲线的形状,因此具有很强的抗干扰能力。

uo=土Uz,

RP3调节放大倍数。

电子设计大赛编程,51单片机,电赛,嵌入式,51单片机,单片机,嵌入式硬件,硬件工程,Powered by 金山文档
三角波发生电路

利用集成运放构成积分器,然后对方波信号进行运算产生三角波。

R7是防止积分电路饱和的反馈电阻,它的大小需要比R1大两个数量级,这样就不会影响积分波形,R7越大三角波越往上。RP3和R5与E1的值决定三角波斜率,因此调节RP3可以改变三角波的幅值。

电子设计大赛编程,51单片机,电赛,嵌入式,51单片机,单片机,嵌入式硬件,硬件工程,Powered by 金山文档
  • 软件与硬件桥接——电路开关设计

用继电器模块作为开关,对电路三种输出波形进行控制。由于继电器模块触发电压为3.3V~5V,进而可用控制单片机引脚输出的高低电平的方法来控制继电器的开关,从而实现对输出波形的智能化控制文章来源地址https://www.toymoban.com/news/detail-756471.html

三位一体原理图

电子设计大赛编程,51单片机,电赛,嵌入式,51单片机,单片机,嵌入式硬件,硬件工程,Powered by 金山文档

到了这里,关于大一电赛:51单片机(状态机编程)——控制外部开关(继电器)达到自定义输出波的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 51单片机控制键盘

    键盘是电子系统中人机对话的重要组成部分,是人向机器发出指令、输入信息的必须设备 键盘在单片机应用系统中是使用最广泛的一种数据 输入设备 。键盘是由多个 按键 组成的。 按键通常是一种常开型开关,常态下按键的两个触点处于 断开 状态,按下按键时它们才闭合

    2024年02月02日
    浏览(56)
  • 【蓝桥杯_学习_51单片机】矩阵键盘 状态机法

    一.基础知识 在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式 采用逐行或逐列的“扫描”,就可以读出任何位置按键的状态 矩阵键盘和独立按键一样,也需要进行消抖处理! 于此补充一下抖动的含义: 对于机械开关,当机械触点断开、闭合时,

    2023年04月09日
    浏览(43)
  • 四、51单片机控制独立按键

    按键相关知识。 1.1、按键工作原理 (1)按键内部是机械结构,也就是内部是没有电路的。按键对外表现位四个引脚,但本质上只是两个,引脚是两两连在一起的。按键按下内部引脚导通,松开内部断开。 (2)电路连接与原理图中图标。 按键一端接地,一端接单片机IO口。  (3)按

    2023年04月14日
    浏览(53)
  • 五、51单片机控制矩阵按键

    1.1、矩阵按键原理分析 这里矩阵按键为4*4的矩阵按键。 (1)矩阵按键横向和纵向分割。 (2)按键两端分别接不同的IO引脚。 (3)按键物理作用不变:按下按键两端接通,弹起按键两端断开。 1.2、矩阵按键的工作过程 JP4接P3端口,JP4_8接P3^7...JP4_1接P3^0。 (1)IO端口(P3)先输出0x0f,按键列

    2023年04月20日
    浏览(54)
  • 51单片机IO口控制

    原理:根据电路图,指向IO口的引脚;拉低电平,灯亮、 如图: [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zfco4IjK-1690308697530)(C:/Users/xie19/Pictures/Camera Roll/屏幕截图 2023-07-19 014128.png)] [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下

    2024年02月15日
    浏览(32)
  • 如何使用单片机点亮LED灯,并使用按键控制[51单片机]

    首先先看一下我的板子,如果我们板子不相同,可能操作也不太相同 我们就不讲底层原理了,直接看,我们可以看到板子上有 8个LED灯   那这个8个LED用什么来控制呢,我们先看底层的线路图,所有的LEDD都连接到了P2带后缀的接口上, 那么只需要操作这几个接口的高低电频,

    2024年02月05日
    浏览(35)
  • 51单片机按键控制LED亮灭

    通过单片机按键控制LED亮灭与传统电路的物理逻辑不同,在物理逻辑中开关控制电路的通断来控制LED的亮灭,而通过单片机完成该项目至于要不断地读取按键所连接IO口的电平来判断对LED连接的IO口输出的电平即可。 原理图如下:  根据原理图,我们可以发现按键按下时P2.1口

    2023年04月18日
    浏览(43)
  • 51单片机按键控制流水灯

    1独立按键的原理图 按键所对应的引脚为P3的0、1、2、3引脚口,并且这里总共有四个独立按键,它们公共的一段都接到了 GND 电源的负极。这样我们就知道按键上电的默认电平为高电平。所以我们只需要控制按键按下时给一个低电平0,不按下时默认高电平1就行。  2按键控制

    2024年02月11日
    浏览(43)
  • 51单片机-按键控制led灯

    1.开发环境介绍 使用C语言,环境为keil Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,与汇编相比,C语言在功能上、结构性、可读性、可维护性上有明显的优势,因而易学易用. 什么是单片机 单片机(Single-Chip Microcomputer)是一种集成电路芯片,把具

    2024年02月09日
    浏览(37)
  • 二、51单片机控制数码管

    (1)数码管的外观: 数码管可分为单个的,联排的(2位、4位、8位) (2)数码管的作用: 数码管是显示器件,是用来显示数字的。 (1)数码管的亮灭是由内部的照明LED的亮灭实现的。 (2)一位数码管内部有八颗LED灯,利用内部的LED灯的亮和灭让数码管显示不同的数字。 (1)驱动方法的

    2023年04月09日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包