STC89C52RC/LE52RC

芯片手册

STC89C52

原理图

扩展版原理图

扩展版原理图

LED灯

点亮LED灯

# include <STC89C5xRC.H>
void main(){
		//将LED连接的P00端口设置为0
		P00 =0;
		while(1);
}

LED灯闪烁

#include <STC89C5xRC.H> // 包含STC89C52RC系列单片机寄存器定义头文件
#include <INTRINS.H>    // 包含内部函数库(提供_nop_()空指令)

/* 类型重定义(增强可读性)*/
typedef unsigned char u8;  // 定义无符号8位数据类型(范围0~255)
typedef unsigned int u16;  // 定义无符号16位数据类型(范围0~65535)
void main()
{
    // 变量初始化
    u8 temp = 0x01;  // 初始化LED位置(二进制00000001,对应最右侧LED)  
    P46 = 0;         // 关闭蜂鸣器(硬件设计缺陷,P4.6低电平关闭蜂鸣器)
                     // 如果不设置,上电时可能产生噪音
    while (1)        // 主循环(单片机程序必须包含无限循环)
    {
        /* LED显示控制 */
        P0 = ~temp;  // 输出到P0口控制LED:
                     // - 取反操作是因为采用共阳接法(端口输出0时LED亮)
                     // - 例如temp=0x01(00000001),取反后=0xFE(11111110),
                     //   即P0.0输出0,对应LED点亮
        /* 更新LED位置 */
        temp <<= 1;  // 左移一位,实现LED流水效果
                     // 例如:0x01→0x02→0x04→...→0x80   
        /* 循环检测 */
        if (temp == 0) // 当左移超出8位时(0x80<<1会变成0x00)
        {
            temp = 0x01; // 重新从最右侧开始
        }
        
        /* 延时控制流水速度 */
        Delayms(100); // 延时100ms(控制LED移动速度)
    }
}

跑马灯

#include <STC89C5xRC.H>  // 包含STC89C52RC系列单片机头文件
#include <INTRINS.H>     // 包含 intrinsics 函数(如_nop_)

typedef unsigned char u8;   // 定义无符号8位数据类型(0~255)
typedef unsigned int u16;   // 定义无符号16位数据类型(0~65535)

// 函数声明
void Delayms(u16 count);    // 毫秒级延时函数声明

void main()
{
    // 变量初始化
    u8 temp = 0x01;     // 初始灯位(00000001,最右侧LED亮)
    bit is_left = 1;    // 方向标志(1=左移,0=右移)

    while (1)           // 主循环
    {
        P0 = ~temp;     // 输出到P0口(取反因为LED共阳接法)
        
        // 根据移动方向更新灯位
        if (is_left) {
            temp <<= 1; // 左移一位(LED向左移动)
        } else {
            temp >>= 1; // 右移一位(LED向右移动)
        }

        // 检测边界条件并改变方向
        if (temp == 0x80) { // 当移动到最左端(10000000)
            is_left = 0;     // 改为右移方向
        }
        if (temp == 0x01) {  // 当移动到最右端(00000001)
            is_left = 1;      // 改为左移方向
        }

        Delayms(100);    // 延时100ms控制移动速度
    }
}

使用定时器中断设计的跑马灯

#include "Int_FlowLed.h"

static void Int_FlowLed_Refresh(){
    static u8 count=100;
    static u8 temp =0x01;
    static bit is_left =1;

    if(count==100){
        P0=~temp;
        if(is_left==1){
            temp<<=1;
        }
        if(is_left==0){
            temp>>=1;
        }
        if(temp==0x01){
            is_left=1;
        }
        if(temp==0x80){
            is_left=0;
        }
    }
    count--;
    if (count==0)
    {
        count=100;
    }

    
}
void Int_Flowed_Init(){
    P34=1;
    Dri_Timer0_init();
    Dri_Timer0_RegisterCallback(Int_FlowLed_Refresh);
}


#ifndef __INT_FLOWL_H__
#define __INT_FLOWL_H__

#include "..\Com\Com_Util.h"
#include "..\Dir\Dri_ Timer0.h"

void Int_Flowed_Init();

#endif

数码管

数码管初始化、位选、管选、显示数字、刷新

#ifndef __INT_DIGITALTUBE_H__
#define __INT_DIGITALTUBE_H__

#include "..\Com\Com_Util.h"

/**
 * @brief 数码管初始化
 */
void Int_DigitalTube_Init();

/**
 * @brief 将指定的整数设置到数码管显示缓存中(digital_buffer数组)
 * 
 * @param number 
 */
void Int_DigitalTube_setBuffer(u32 number);

/**
 * @brief 数码管指定位置指定数字
 *
 * @param pos     位置,使用数字0~7分别表示从左边数第1到到第8个
 * @param code    数字的段选信息
 */
void Int_DigitalTube_Single(u8 pos, u8 number_code);

/**
 * @brief 刷新数码管
 *
 */
void Int_DigitalTube_Refresh();

#include "Int_DigitalTube.h"

// 定义数组,保存每个数字的段选信息
static u8 s_number_codes[10] = {
    0x3F, // 0
    0x06, // 1
    0x5B, // 2
    0x4F, // 3
    0x66, // 4
    0x6D, // 5
    0x7D, // 6
    0x07, // 7
    0x7F, // 8
    0x6F  // 9
};

// 定义数组,8个元素,对应数码管8个位置; 每个元素存储数字的段选信息
static u8 s_digital_buffer[8];
/**
 * @brief 将指定的整数设置到数码管显示缓存中(s_digital_buffer数组)
 *
 * @param number
 */
void Int_DigitalTube_setBuffer(u32 number)
{
    u8 i;

    // 1. 清空之前的显示内容
    for (i = 0; i < 8; i++)
    {
        s_digital_buffer[i] = 0x00;
    }

    // 2. 依次取出number中每位上的数,将其段选信息存储数组;最低位存入最后一个元素
    for (i = 7;; i--)
    {
        // 取出当前位上的数,将其段选信息存入数组指定位置
        s_digital_buffer[i] = s_number_codes[number % 10];
        // 处理number,去掉最低位
        number /= 10;
        // 如果number变为0,说明数字已经取完,停止循环
        if (number == 0 || i == 0)
        {
            break;
        }
    }
}

/**
 * @brief 数码管指定位置指定数字
 *
 * @param pos     位置,使用数字0~7分别表示从左边数第1到到第8个
 * @param code    数字的段选信息
 */
void Int_DigitalTube_Single(u8 pos, u8 number_code)
{
    // 1. 位选 -------------------------------
    // 1.1 pos 左移3位,  与P15、P14、P13 对齐
    pos <<= 3;
    // 1.2 将P1的P15、P14、P13三位置0,其他位保持不变, P1 & 0b11000111
    P1 &= 0xC7;
    // 1.3 将pos上的三位有效数, 赋值到 P15、P14、P13 位置上
    P1 |= pos;

    // 2. 段选 --------------------------------
    P0 = number_code;
}

/**
 * @brief 刷新数码管
 *
 */
void Int_DigitalTube_Refresh()
{
    // 循环0到7
    u8 i;
    for (i = 0; i <= 7; i++)
    {
        Int_DigitalTube_Single(i, s_digital_buffer[i]);
        Delayms(1);
    }
}

数码管显示小数,基于上面“数码管初始化、位选、管选、显示数字、刷新”的代码

/**
 * @brief 将指定的整数设置到数码管显示缓存中(s_digital_buffer数组)
 *
 * @param number
 */
void Int_DigitalTube_setBuffer(float number)
{
    u8 i;
    u8 number_str_index;
    bit is_dot=0;
    char number_str[17]; 

    // 1. 清空之前的显示内容
    for (i = 0; i < 8; i++)
    {
        s_digital_buffer[i] = 0x00; 
    }
    sprintf(number_str,"%f",number);
    number_str_index = strlen(number_str)-1;
    while (number_str[number_str_index]==48)
    {
        number_str_index--;
    }
    // 2. 依次取出number中每位上的数,将其段选信息存储数组;最低位存入最后一个元素
    for (i = 7;; i--,number_str_index--)
    {
        if(number_str[number_str_index]==46){
            is_dot=1;
            i++;
            continue;
        }
        if (is_dot==1)
        {
            s_digital_buffer[i]=s_number_codes[number_str[number_str_index]-48]+0x80;
            is_dot=0;
        }else{
            s_digital_buffer[i]=s_number_codes[number_str[number_str_index]-48];
        }
        if (i == 0||number_str_index == 0)
        {
            break;
        }
    }
}

定时器实现数码管数字的现时

#include "Int_DigitalTube.h"

// 定义数组,保存每个数字的段选信息
static u8 s_number_codes[10] = {
    0x3F, // 0
    0x06, // 1
    0x5B, // 2
    0x4F, // 3
    0x66, // 4
    0x6D, // 5
    0x7D, // 6
    0x07, // 7
    0x7F, // 8
    0x6F  // 9
};

// 定义数组,8个元素,对应数码管8个位置; 每个元素存储数字的段选信息
static u8 s_digital_buffer[8];


/**
 * @brief 数码管指定位置指定数字
 *
 * @param pos     位置,使用数字0~7分别表示从左边数第1到到第8个
 * @param code    数字的段选信息
 */
void Int_DigitalTube_Single(u8 pos, u8 number_code)
{
    // 1. 位选 -------------------------------
    // 1.1 pos 左移3位,  与P15、P14、P13 对齐
    pos <<= 3;
    // 1.2 将P1的P15、P14、P13三位置0,其他位保持不变, P1 & 0b11000111
    P1 &= 0xC7;
    // 1.3 将pos上的三位有效数, 赋值到 P15、P14、P13 位置上
    P1 |= pos;

    // 2. 段选 --------------------------------
    P0 = number_code;
}

/**
 * @brief 刷新数码管
 *
 */
void Int_DigitalTube_Refresh()
{
    // 循环0到7
    static u8 i=0;
    Int_DigitalTube_Single(i, s_digital_buffer[i]);
    i++;
    if(i==8){
        i=0;
    }
}
/**
 * @brief 数码管初始化
 */
void Int_DigitalTube_Init()
{
    // 打开数码管开关
    P36 = 0;
    // 关闭流水灯
    P34 = 0;
    Dri_Timer0_init();
    Dri_Timer0_RegisterCallback(Int_DigitalTube_Refresh);
}

/**
 * @brief 将指定的整数设置到数码管显示缓存中(s_digital_buffer数组)
 *
 * @param number
 */
void Int_DigitalTube_setBuffer(u32 number)
{
    u8 i;

    // 1. 清空之前的显示内容
    for (i = 0; i < 8; i++)
    {
        s_digital_buffer[i] = 0x00;
    }

    // 2. 依次取出number中每位上的数,将其段选信息存储数组;最低位存入最后一个元素
    for (i = 7;; i--)
    {
        // 取出当前位上的数,将其段选信息存入数组指定位置
        s_digital_buffer[i] = s_number_codes[number % 10];
        // 处理number,去掉最低位
        number /= 10;
        // 如果number变为0,说明数字已经取完,停止循环
        if (number == 0 || i == 0)
        {
            break;
        }
    }
}

void Int_DigitalTube_setPointBuffer(double number){
    u8 i;
    u8 number_str_index;
    bit is_dot=0;
    char number_str[17]; 

    // 1. 清空之前的显示内容
    for (i = 0; i < 8; i++)
    {
        s_digital_buffer[i] = 0x00;
    }
    sprintf(number_str,"%f",number);
    number_str_index = strlen(number_str)-1;
    while (number_str[number_str_index]==48)
    {
        number_str_index--;
    }
    // 2. 依次取出number中每位上的数,将其段选信息存储数组;最低位存入最后一个元素
    for (i = 7;; i--,number_str_index--)
    {
        if(number_str[number_str_index]==46){
            is_dot=1;
            i++;
            continue;
        }
        if (is_dot==1)
        {
            s_digital_buffer[i]=s_number_codes[number_str[number_str_index]-48]+0x80;
            is_dot=0;
        }else{
            s_digital_buffer[i]=s_number_codes[number_str[number_str_index]-48];
        }
        if (i == 0||number_str_index == 0)
        {
            break;
        }
    }
}



#ifndef __INT_DIGITALTUBE_H__
#define __INT_DIGITALTUBE_H__

#include <STDIO.H>
#include <STRING.H>
#include "..\Com\Com_Util.h"
#include "..\Dir\Dri_ Timer0.h"


void Int_DigitalTube_Init();

void Int_DigitalTube_setBuffer(u32 number);

void Int_DigitalTube_setPointBuffer(double number);


#endif

独立按键

检测那个独立按键被按下

#ifndef __INK_KEY_H__
#define __INK_KEY_H__
#include "..\Com\Com_Util.h" 

 // 按键引脚定义(根据实际硬件连接)
 #define SW1 P42  // 按键1(P4.2)
 #define SW2 P43  // 按键2(P4.3)
 #define SW3 P32  // 按键3(P3.2)
 #define SW4 P33  // 按键4(P3.3)

 bit Int_Key_IsSW1Pressed();

 bit Int_Key_IsSW2Pressed();

 bit Int_Key_IsSW3Pressed();

 bit Int_Key_IsSW4Pressed();
#endif
# include "Int_Key.h"

bit Int_Key_IsSW1Pressed(){
    if(SW1==0){
        Delayms(10);
        if(SW1==0){
            while (SW1==0);
            return 1;
        }
    }
    return 0;
}

bit Int_Key_IsSW2Pressed()
{
    if(SW2==0){
        Delayms(10);
        if(SW2==0){
            while (SW2==0);
            return 1;
        }
    }
    return 0;
}

bit Int_Key_IsSW3Pressed()
{
    if(SW3==0){
        Delayms(10);
        if(SW3==0){
            while (SW3==0);
            return 1;
        }
    }
    return 0;
}

bit Int_Key_IsSW4Pressed()
{
    if(SW4==0){
        Delayms(10);
        if(SW4==0){
            while (SW4==0);
            return 1;
        }
    }
    return 0;
}

检测矩阵按键,那个被按下

#ifndef __INT_MATRIX_KEY__
#define __INT_MATRIX_KEY__

#include "..\Com\Com_Util.h"

u8 Int_MatrixKey_Check_Key();

 #endif
# include "Int_MatrixKey.h"

static u8 s_lines[4]={0xFE,0xFD,0xFB,0xF7};

u8 Int_MatrixKey_Check_Key()
{

    u8 i;
    for (i = 0; i < 4; i++)
    {
        P2=s_lines[i];
        if (P24==0)
        {
            Delayms(10);
            while (P24==0);
            return 5+i*4; 
        }
        if (P25==0)
        {
            Delayms(10);
            while (P25==0);
            return 6+i*4;
        }
        if (P26==0)
        {
            Delayms(10);
            while (P26==0);
            return 7+i*4; 
        }
        if (P27==0)
        {
            Delayms(10);
            while (P27==0);
            return 8+i*4; 
        }
        
    }
    return 0;   
}

蜂鸣器

让蜂鸣器发出声音

#ifndef __INT_BUZZER_H__
#define __INT_BUZZER_H__

#include "..\Com\Com_Util.h"

void Int_Buzzer_Buzz(u16 ms);
#endif
#include "Int_Buzzer.h"
void Int_Buzzer_Buzz(u16 ms){
    while (ms)
    {
        ms--;
        P46=~P46;
        Delayms(1);
    } 
    P46=0;
}

让蜂鸣器发出不同大小的声音

#ifndef __INT_BUZZER_H__
#define __INT_BUZZER_H__

#include "..\Com\Com_Util.h"

void Int_Buzzer_Buzz(u16 ms);
void Int_Buzzer_BuzzLoud(u16 us);
void Int_Buzzer_BuzzLow(u16 us);
#endif
#include "Int_Buzzer.h"


void Int_Buzzer_Buzz(u16 ms){
    while (ms)
    {
        ms--;
        P46=~P46;
        Delayms(1);
    } 
    P46=0;
}

void Int_Buzzer_BuzzLoud(u16 us){
    while (us)
    {
        us-=2;
        P46=1;
        Delay100us(19);
        P46=0;
        Delay100us(1);
    } 
    P46=0;
}

void Int_Buzzer_BuzzLow(u16 us){
    while (us)
    {
        us-=2;
        P46=1;
        Delay100us(1);
        P46=0;
        Delay100us(19);
    } 
    P46=0;
}

让蜂鸣器发出不同类型的声音

#ifndef __INT_BUZZER_H__
#define __INT_BUZZER_H__

#include "..\Com\Com_Util.h"
void Int_Buzzer_BuzzMusic(u16 ms,u8 type);
#endif
#include "Int_Buzzer.h"
void Int_Buzzer_BuzzMusic(u16 ms, u8 type)
{
    u16 count=0;
    u8 t=0;
    switch (type)
    {
    case 1:
        t = 100000 / (2 * 400);
        break;
    case 2:
        t = 100000 / (2 * 450);
        break;
    case 3:
        t = 100000 / (2 *506);
        break;
    case 4:
        t = 100000 / (2 * 540);
        break;
    case 5:
        t = 100000 / (2 * 600);
        break;
    case 6:
        t = 100000 / (2 * 675);
        break;
    case 7:
        t = 100000 / (2 * 759);
        break;
    case 8:
        t = 100000 / (2 * 800);
        break;
    default:t = 100000 / (2 * 1000);
        break;
    }
    count = (ms*100)/t;
    while (count)
    {
        count--;
        P46 = ~P46;
        Delayms(t);
    }
    P46 = 0;
}

中断

中断控制信息获取

外部中断

开启中断总开关
开启特定的外部中断
设置中断的触发方式
设置中断的优先级
设置中断服务程序
在中断结构处找到使能开关(EA),并判断其所处的寄存器能否按位寻址
在这里插入图片描述
在这里插入图片描述
设置具体开放那个中断,找到开放具体中断的控制位,判单其是否可以按位寻址
在这里插入图片描述
在这里插入图片描述
找到控制位,判断其寄存器是否可以按位寻址,设置要开启的中断的触发方式

在这里插入图片描述
在这里插入图片描述
找到功能位,判断其寄存器是否可以按位寻址,设置中断的优先级
在这里插入图片描述
在这里插入图片描述
判断中断类型,找到中编号,编写中断服务程序
在这里插入图片描述

#include ".\Com\Com_Util.h"  
#include ".\Int\Int_Key.h"
#include ".\Int\Int_Buzzer.h"
#include ".\Int\Int_DigitalTube.h"
#include ".\Int\Int_MatrixKey.h"
 void main()
 {
    P46=0;

    EA =1;

    EX0  =1;

    IT0=1;

    PX0=1;
    IPH|=0x01;

    while (1);
 }

 void Interrupt_program() interrupt 0{
    P00 =~P00;
 }



定时器中断

开启中断总开关
开启特定的中断
设置中断的触发方式
设置中断的优先级
设置中断服务程序
开启中断开关
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
封装的代码

#include "Dri_ Timer0.h"

static Timer_Callback s_callback[MAX_CALLBACK_COUNT]={NULL,NULL,NULL,NULL};
static u16 s_count=1000;


void Dri_Timer0_init(){
    EA=1;
    ET0=1;

    TMOD &=0xF0;
    TMOD |=0x01;

    TL0=64616;
    TH0=64616>>8;

    IPH |=0x02;
    PT0=0;

    TR0=1;
}

bit Dri_Timer0_RegisterCallback(Timer_Callback cb){
    u8 i;
    for (i = 0; i < MAX_CALLBACK_COUNT; i++)
    {
        if (s_callback[i]==cb)
        {
            return 0;
        }   
    }

    for (i = 0; i < MAX_CALLBACK_COUNT; i++)
    {
        if (s_callback[i]==NULL)
        {
            s_callback[i]=cb;
            return 1;
        }   
    }
    return 0;
}

bit Dri_Timer0_DeleteRegisterCallback(Timer_Callback cb){
    u8 i;
    for (i = 0; i < MAX_CALLBACK_COUNT; i++)
    {
        if (s_callback[i]==cb)
        {
            s_callback[i]=NULL;
            return 1;
        }   
    }
    return 0;
}

void Dri_Timer0_Handler() interrupt 1{
    u8 i;
    TL0=64616;
    TH0=64616>>8;
    for (i = 0; i <MAX_CALLBACK_COUNT; i++)
    {
        if(s_callback[i]!=NULL){
            s_callback[i]();
        }
    }
}


#ifndef __Dri_TIMER0_H__
#define __Dri_TIMER0_H__

#include "..\Com\Com_Util.h"
#include "STDIO.H"

#define MAX_CALLBACK_COUNT 4
typedef void (*Timer_Callback)(void);

void Dri_Timer0_init();
bit Dri_Timer0_RegisterCallback(Timer_Callback cb);
bit Dri_Timer0_DeleteRegisterCallback(Timer_Callback cb);

#endif

串口中断

工具包

延时函数,延时ms级别

#ifndef __COM_UTIL_H__
#define __COM_UTIL_H__

#include <STC89C5xRC.H>
#include <INTRINS.H>

// 类型别名
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;

/**
 * @brief 延时函数,指定延时多少毫秒
 *
 * @param count 指定多少毫秒
 */
void Delayms(u16 count);

#endif
#include "Com_Util.h"

// 延时函数,指定延时多少毫秒
void Delayms(u16 count)
{
    u8 data i, j;
    while (count)
    {
        _nop_();
        i = 2;
        j = 199;
        do
        {
            while (--j)
                ;
        } while (--i);
        count--;
    }
}

延时函数,延时us级,基于延时ms级的代码

void Delay100us(u16 count){
	unsigned char data i;
    while (count)
    {
        _nop_();
        i = 43;
        while (--i);
        count--;
    }
}
内容概要:本文围绕无人机自主水下传感网络(UASNs)中自主水下航行器(AUV)的路径规划问题展开研究,提出采用遗传算法(Genetic Algorithm, GA)进行优化求解,并通过Matlab代码实现仿真验证。研究重点在于利用遗传算法的全局搜索能力,解决水下复杂环境中AUV的高效路径规划问题,提升数据采集效率与网络性能。文中详细阐述了问题建模、适应度函数设计、约束条件处理及算法实现流程,展示了GA在应对多目标、非线性、动态变化水下环境中的可行性与有效性。同时,文档还列举了大量相关科研方向与Matlab仿真实例,涵盖路径规划、电力系统、机器学习、通信优化等多个领域,体现出较强的技术综合性与科研指【UASNs、AUV】无人机自主水下传感网络中遗传算法的路径规划问题研究(Matlab代码实现)导价值。; 适合人群:具备一定Matlab编程基础,从事智能优化算法、路径规划、水下传感网络或相关领域研究的研究生、科研人员及工程技术人员,尤其适合正在开展无人机、AUV或智能优化应用研究的1-5年经验研究人员。; 使用场景及目标:①学习遗传算法在复杂路径规划问题中的建模与实现方法;②掌握Matlab在UASNs与AUV路径规划中的仿真技术;③借鉴多领域科研案例拓展研究思路,推动算法在实际水下探测、环境监测、军事侦察等场景的应用。; 阅读建议:建议结合提供的Matlab代码进行实践操作,重点关注遗传算法的编码方式、交叉变异策略与适应度函数设计;同时可参考文中列出的其他研究方向进行横向拓展,强化对智能优化算法在多学科交叉应用的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值