B001-Atmega16-数码管

一步步完成数码管

-------------------------------------------------------------------------------------------------------------------------------------

开发环境:AVR Studio 4.19 + avr-toolchain-installer-3.4.1.1195-win32.win32.x86

芯片型号:ATmega16

芯片主频:8MHz

-------------------------------------------------------------------------------------------------------------------------------------

第一步: 产生1ms的时基

说明:

1、使用定时器0的CTC中断产生1ms的时基信号,CTC模式下时自动重装初值、比较方便。

2、使用OCF0中断、不需要OC0引脚输出波形。

代码:

Drv_Timer.h中的相关定义:

// ----------------------------------------------------------------------------------------------------------
// 定时器中断模式
typedef enum
{
    INT_MODE_TOV = 0,
    INT_MODE_OCF = 1,
    INT_MODE_ICF = 2,
    INT_MODE_OCF1A = 3,
    INT_MODE_OCF1B = 4
} TIMER_INT_MODE;

// 定时器比较匹配引脚输出模式
typedef enum
{
    COM_MODE_NONE   = 0,
    COM_MODE_TOGGLE = 1,
    COM_MODE_CLEAR  = 2,
    COM_MODE_SET    = 3,
} TIMER_COM_MODE;

// 定时器0
typedef enum
{
    T0_WGM_NOMAL     = 0,
    T0_WGM_PHASE_PWM = 1,
    T0_WGM_CTC       = 2,
    T0_WGM_FAST_PWM  = 3,

    T0_CLK_SOURCE_NONE     = 0,
    T0_CLK_SOURCE_CLK_1    = 1,
    T0_CLK_SOURCE_CLK_8    = 2,
    T0_CLK_SOURCE_CLK_64   = 3,
    T0_CLK_SOURCE_CLK_256  = 4,
    T0_CLK_SOURCE_CLK_1024 = 5,
    T0_CLK_SOURCE_T0_FALL  = 6,
    T0_CLK_SOURCE_T0_RAISE = 7
} TIMER0_MODE;

Drv_Timer.c中的操作函数:

// ==========================================================================================================
// TIMER0 初始化
//
// 参数:wave_mode       工作模式/波形产生模式选择
//       OC_mode         比较匹配/PWM输出模式选择
//       clk_source      时钟源和预分频选择
//
// 写TCCR0时需要清除bit7=FOC0
//
// 定时器溢出周期 T = ((1.0 / 8000000) * 1000000) * clk_source * 256 ( @ 8MHz )
// ==========================================================================================================
void Drv_Timer0_init(const uint8_t wave_mode, const uint8_t com_mode, const uint8_t clk_source)
{
    uint8_t wgm00,wgm01;

    wgm00 =  wave_mode & 0x01;
    wgm01 = (wave_mode & 0x02) >> 1;

    // 写TCCR0时需要将bit7=FOC0清0
    TCCR0 = (wgm00 << 6)|               // 工作模式/波形产生模式选择
            (wgm01 << 3)|
            ((com_mode & 0x03)   << 4)| // 比较匹配/PWM输出模式选择
            ((clk_source & 0x07) << 0); // 时钟源和预分频选择
}

// ==========================================================================================================
// TIMER0 中断使能
//
// 参数:int_mode  = INT_MODE_TOV 或 INT_MODE_OCF 或 INT_MODE_ICF
//       enable    = ENABLE 或 DISABLE
//
// 说明:
// 1、OC0引脚要先配置成比较匹配引脚、再修改数据方向寄存器DDB3
// 2、可以单独使能/禁止一种模式的中断
//
// ==========================================================================================================
void Drv_Timer0_INT_Enable(const uint8_t int_mode, const uint8_t enable)
{
    if(INT_MODE_TOV == int_mode)
    {
        if(DISABLE == enable)
        {
            TIMSK &= ~(1 << TOIE0);
        }
        else
        {
            TIMSK |=  (1 << TOIE0);
        }
        TIFR |= (1 << TOV0);
        return ;
    }
    if(INT_MODE_OCF == int_mode)
    {
        if(DISABLE == enable)
        {
            TIMSK &= ~(1 << OCIE0);
        }
        else
        {
            TIMSK |=  (1 << OCIE0);
        }
        TIFR |= (1 << OCF0);
    }
}

// ==========================================================================================================
//      设置TCNT0和OCR0的值
//
// (1). 在比较匹配下、OCR0需要在TCNT0被设置之后设置
// ==========================================================================================================
void Drv_Timer0_set_TCNT0_OCR0(const uint8_t tcnt0, const uint8_t ocr0)
{
    TCNT0 = tcnt0;
    OCR0  = ocr0;
}

sys_timer.c中设置定时器0,并在OCF0中断中使用PA1测试定时时间:

#include <avr/interrupt.h>
#include "Drv_Timer.h"
#include "sys_timer.h"

// ==========================================================================================================
//      系统任务定时器
//
// (1). 使用Timer0产生1ms的时标
//      定时周期 T = ((1.0/8000000)*1000000)*64*(124+1) = 1000us = 1ms
//
// ==========================================================================================================
void sys_timer_init(void)
{
    // 定时器0初始化:CTC模式、OC0引脚不连接、64预分频
    Drv_Timer0_init(T0_WGM_CTC, COM_MODE_NONE, T0_CLK_SOURCE_CLK_64);
    // 设置初值:TCNT0=0、OCR0=122
    Drv_Timer0_set_TCNT0_OCR0(0, 122);
    // 使能OCF0中断
    Drv_Timer0_INT_Enable(INT_MODE_OCF, ENABLE);
}

// ==========================================================================================================
//      系统定时器中断
//
// (1). 使用Timer0的CTC中断调度各个任务
//
// ==========================================================================================================
ISR(TIMER0_COMP_vect)
{
    PORTA ^= (1 << PA1); // 使用PA1测试定时周期
}

main.c中完成初始化,并设置IO:

// ==========================================================================================================
// 主函数
// ==========================================================================================================
#include <avr/io.h>
#include "Drv_Timer.h"
#include "system.h"
#include "sys_timer.h"
#include "config.h"

// ==========================================================================================================
// main函数
// ==========================================================================================================
int main(void)
{
    // ------------------------------------------------------------------------------------------------------
    // 关全局中断
    cli();

    // 系统初始化 ( 包含sys_timer_init() )
    sys_init();

    DDRA  |=   (1 << DDA0) | (1 << DDA1);
    PORTA &= ~((1 << PA0 ) | (1 << PA1 ));

    // OC0/PB3初始化为输出0
    DDRB  |=   (1 << DDB3);
    PORTB &= ~((1 << PB3 ));

    // 开全局中断
    sei();

    // ------------------------------------------------------------------------------------------------------
    while(1)
    {
    }
    return 0;
}

测试结果:

示波器输出如下:

1、PA1引脚输出方波,周期是2*1.0ms,引脚电平每隔1.0ms翻转一次。

使用OCR0=124、计算得到精确的1.0ms,但进入中断函数是需要花费时间的。

所以这里使用稍小的OCR0=122,让从中断产生到进入中断函数为止的时间更精确为1.0ms

有些计时功能会积累时基的误差、越到后面积累的误差越大,所以这里能精确就尽量做的精确些。

到此、1.0ms定时完成。

2、OC0引脚没有波形输出,我们也不需要用到这个引脚,就让他保持普通IO的特性吧。

-------------------------------------------------------------------------------------------------------------------------------------

第二步: 静态显示

说明:

1、这一步需要根据电路图、在指定的数码管上显示指定的符号。

1、数码管驱动电路图:

电路中使用的是共阴极数码管:

1个数码管有8个LED,称为8段数码管

共阴的意思是:

1、8个LED的负极都连接在com引脚

2、8个LED的正极对应8个引脚,编号分别为[Dp,g,f,e,d,c,b,a]

数码管的电压和电流:

点亮1个数码管所需的电流需要查看厂家给的数码管数据手册才知道。

如果没有数据手册,可以预估为10-20mA,电压预估为2V

和普通LED一样、必要的时候需要加限流电阻

在动态扫描中、每个数码管都是点亮几毫秒熄灭几十毫秒,并非一直点亮,所以不加限流电阻也行,除非是大电流数码管。

数码管的驱动芯片是74HC13874HC573,他们的驱动电流足够点亮1个数码管:

2、共阴极数码管的点亮方式:

1、在引脚a输入高电平,引脚b-Dp输入低电平,在com引脚输入低电平。

那么,段[a]被点亮,段[Dp,g,f,e,d,c,b]都不亮。

也就是说、只有输入状态为高电平的段会被点亮。

2、在引脚b、c输入高电平,引脚a、d-Dp输入低电平,在com引脚输入低电平。

那么,段[b,c]被点亮,段[a,d,e,f,g,Dp]都不亮。

这时得到的图像就是数字‘1‘的图像,对应的段码[Dp,g,f,e,d,c,b,a]=0b00000110=0x06

3、在引脚a、b、g、e、d输入高电平,引脚c、f、Dp输入低电平,在com引脚输入低电平。

那么,段[a,b,g,e,d]被点亮,段[c,f,Dp]都不亮。

这时得到的图像就是数字‘2‘的图像,对应的段码[Dp,g,f,e,d,c,b,a]=0b01011011=0x5B

4、也就是说、com口为低电平的数码管被使能,如果它的段选中有不为0的段,这个段就会被点亮

3、段码:

1、16十六进制数字[0-9,A-F]的段码如下:

static const uint8_t segment_code[17]=
{
    0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,  // 0 - 9
    0x77,0x7c,0x39,0x5e,0x79,0x71,                      // A - F
    0x00                                                // 全部熄灭
};

最后一个值0x00就是全部LED段都不亮,用来熄灭数码管上所有LED段。

在电路中、74HC573的输出和输入保持一致,同时输出电流。

将这些段码赋予PORTB口就可以在74HC573的输出同样的电平数据,使得段[Dp,g,f,e,d,c,b,a]上得到对应的电平,对应的LED段就被点亮。

4、位选:

1、通过拉低某个数码管的com口、来使能这个数码管,这称为位选。

8com口都连接在74HC138上,输出为低电平的引脚上连接的数码管将被选中。

74HC138的输入输出表如下:

在电路中,使用PORTA[2:0]来对应74HC138的输入[A2,A0]

74HC138的输入[A2,A0]映射到PORTA[2:0]就是下面的数组,用来分别使能第0位第7位数码管:

static const uint8_t segment_index[8]= { 0,1,2,3,4,5,6,7 };

5、代码:

下面的代码用来在第0号数码管上、显示数字"5"

Mod_LED_display.c

#include <avr/interrupt.h>
#include "Mod_LED_Displayer.h"

// 段码(共阴 == 高电平点亮)
static const uint8_t segment_code[17]=
{
    0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,  // 0 - 9
    0x77,0x7c,0x39,0x5e,0x79,0x71,                      // A - F
    0x00                                                // 全部熄灭
};

// 位码(低电平使能)(使用74HC138选通位选)
// 分别使能第0号到第7号数码管(与之相与(&)来使能)
static const uint8_t segment_index[8]= { 0,1,2,3,4,5,6,7 };

// ==========================================================================================================
// LED数码管硬件初始化
//
// ==========================================================================================================
void Mod_LED_display_init(void)
{
    // 数码位选选使能(74HC138芯片使能)
    DDRC  |= (1 << DDC7);
    PORTC |= (1 << PC7 );
    // 段选控制:PORTB初始化为:输出低电平
    DDRB  = 0xFF;
    PORTB = 0x00;
    // 位选控制:PORTA[2:0]初始化为:输出低电平(选中第0号数码管)
    DDRA  |=   (1 << DDA0) |(1 << DDA1) |(1 << DDA2);
    PORTA &= ~((1 << PA0 ) |(1 << PA1 ) |(1 << PA2 ));

    // LED数码管显示固定的数据 ------------------------------------------------------------------------------
    // 清除数码管显示
    PORTB  = segment_code[16];
    // 修改位选
    PORTA |= segment_index[7];
    PORTA &= segment_index[0];  // 第0号数码管
    // 修改显示
    PORTB  = segment_code[5];   // 数字'5'
}

main.c

// ==========================================================================================================
// 主函数
// ==========================================================================================================
#include <avr/io.h>
#include "Mod_LED_Displayer.h"
#include "sys_timer.h"
#include "system.h"
#include "config.h"

// ==========================================================================================================
// main函数
// ==========================================================================================================
int main(void)
{
    // ------------------------------------------------------------------------------------------------------
    // 关全局中断
    cli();

    // 系统初始化 ( 包含Mod_LED_display_init() )
    sys_init();

    // 开全局中断
    sei();

    // ------------------------------------------------------------------------------------------------------
    while(1)
    {
    }
    return 0;
}

测试结果:

1、现在可以在任一个数码管上、显示任一个十六进制数了。

-------------------------------------------------------------------------------------------------------------------------------------

第三步: 动态扫描

说明:

1、由静态显示到动态扫描经过了以下步骤:

(1). 在第一步的1ms定时中断中、每隔1000ms第0号数码管上显示1个数字,

并依次循环显示16十六进制数,检验所有段码

(2). 在第一步的1ms定时中断中、每隔1000ms切换到下一个数码管,去显示一个固定的数字,

并依次循环切换这8个数码管,检验所有位码

(3). 让8位数码管动态显示数值01234567

也就是切换到第0号数码管时、显示数字‘0‘,后面的一次类推,每隔1ms切换一个数码管。

(4). 最后、让让8位数码管动态显示任意数值,超过8位的数值当然只能显示低8位(十进制)。

最终的代码经过了几次构造,以方便修改用于控制数码管的IO口。

代码如下:

Mod_LED_display.c

#include <avr/interrupt.h>
#include "Mod_LED_Displayer.h"

// 段码(共阴 == 高电平点亮)
static const uint8_t segment_code[17]=
{
    0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,  // 0 - 9
    0x77,0x7c,0x39,0x5e,0x79,0x71,                      // A - F
    0x00                                                // 全部熄灭
};

// 位码(低电平使能)(使用74HC138选通位选)
// 分别使能第0号到第7号数码管(与之相与(&)来使能)
static const uint8_t segment_index[8]= { 0,1,2,3,4,5,6,7 };

// 数码管控制结构
typedef struct
{
    uint8_t *seg_index; // 位选端口的数据
    uint8_t *seg_code;  // 段选端口的数据
    uint8_t  index;     // 使能第index数码管
    uint8_t  data[sizeof(segment_index)];   // 送给[0:7]号数码管去显示的8个数据
}T_SEG_LED_DISPLAY_CTRL,*pT_SEG_LED_DISPLAY_CTRL;

static T_SEG_LED_DISPLAY_CTRL LED_display_ctrl = { .seg_index = (uint8_t *)(&PORTA),
                                                   .seg_code  = (uint8_t *)(&PORTB),
                                                   .index = 0,
                                                   .data  = { 0,1,2,3,4,5,6,7 }
                                                  };
// 使用指针是为了在代码中使用'->'操作符来替代'.'操作符,更直观
static pT_SEG_LED_DISPLAY_CTRL p_LED_display_ctrl = &LED_display_ctrl;

// ==========================================================================================================
// LED数码管硬件初始化
//
// ==========================================================================================================
void Mod_LED_display_init(void)
{
    // ------------------------------------------------------------------------------------------------------
    // 数码管位选使能(74HC138芯片使能)
    DDRC  |= (1 << DDC7);
    PORTC |= (1 << PC7 );
    // 段选控制:PORTB初始化为:输出低电平
    DDRB  = 0xFF;
    PORTB = 0x00;
    // 位选控制:PORTA[2:0]初始化为:输出低电平(选中第0号数码管)
    DDRA  |=   (1 << DDA0) |(1 << DDA1) | (1 << DDA2);
    PORTA &= ~((1 << PA0 ) |(1 << PA1 ) | (1 << PA2 ));
}

// ==========================================================================================================
//      LED数码管显示数据的刷新
//
// (1). 在系统定时器中每隔1ms刷新1次
//
// ==========================================================================================================
void Mod_LED_display_update(void)
{
#if 1
    // 熄灭当前数码管、用来避免余晖
    *p_LED_display_ctrl->seg_code = segment_code[sizeof(segment_code) - 1];
#endif

    // 切换到下1个数码管
    p_LED_display_ctrl->index++;
    if(p_LED_display_ctrl->index > (sizeof(segment_index) - 1))
    {
        p_LED_display_ctrl->index = 0;
    }

    // 修改位选、修改显示
    *p_LED_display_ctrl->seg_index |= segment_index[sizeof(segment_index) - 1];
    *p_LED_display_ctrl->seg_index &= segment_index[p_LED_display_ctrl->index];
    *p_LED_display_ctrl->seg_code   = segment_code[p_LED_display_ctrl->data[segment_index[p_LED_display_ctrl->index]]];
}

// ==========================================================================================================
// LED数码管显示(十进制)
//
// ==========================================================================================================
void Mod_LED_display(uint32_t data)
{
    uint8_t temp  = 0;
    uint8_t index = 0;

    for(index = 0; index < sizeof(segment_index); index++)
    {
        // 取出最低位的数据
        if(0 == data) { temp = 0; }
        else          { temp = data % 10UL; }
        // 保存最低位的数据
        p_LED_display_ctrl->data[sizeof(segment_index) - index - 1] = temp;
        // 丢弃最低位的数据
        if(0 != data) { data = data / 10UL; }
    }
}

// ==========================================================================================================
// LED数码管显示(进制)
//
// 1、可以显示十六进制、以及十六进制以内的进制
//
// ==========================================================================================================
void Mod_LED_display_hex(uint32_t data, uint8_t hex)
{
    uint8_t temp  = 0;
    uint8_t index = 0;

    if((hex > 16) || (hex < 2)) { return ; }

    for(index = 0; index < sizeof(segment_index); index++)
    {
        if(0 == data) { temp = 0; }
        else          { temp = data % hex; }
        p_LED_display_ctrl->data[sizeof(segment_index) - index - 1] = temp;
        if(0 != data) { data = data / hex; }
    }
}

sys_timer.c中,每隔1ms刷新一次数码管:

// ==========================================================================================================
//      系统定时器中断(中断周期=1ms)
//
// (1). 使用Timer0的CTC中断调度各个任务
//
// ==========================================================================================================
ISR(TIMER0_COMP_vect)
{
    Mod_LED_display_update();
}

main.c如下:

// ==========================================================================================================
// 主函数
// ==========================================================================================================
#include <avr/io.h>
#include "Mod_LED_Displayer.h"
#include "sys_timer.h"
#include "system.h"
#include "config.h"

// ==========================================================================================================
// main函数
// ==========================================================================================================
int main(void)
{
    // ------------------------------------------------------------------------------------------------------
    // 关全局中断
    cli();

    // 系统初始化
    sys_init();

    // 开全局中断
    sei();

    Mod_LED_display(123456789);
//    Mod_LED_display_hex(65536, 15);

    // ------------------------------------------------------------------------------------------------------
    while(1)
    {
    }
    return 0;
}

测试结果:

1、显示中没有余晖(重影),不亮的段都是白色。

2、操作函数中还提供了一个根据指定的进制来保存和显示数字的函数Mod_LED_display_hex()

比如Mod_LED_display_hex(65536, 15);就是将十进制数65536按照15进制保存、并显示在数码管上。

数码管上将显示15进制数14641,可以在线进行进制转换、来验证结果:http://tool.oschina.net/hexconvert

在线转换的结果:

3、这里对数码管的操作是一种三段式的操作:初始化 + 前台更新 + 后台API

-------------------------------------------------------------------------------------------------------------------------------------

第四步: 余晖 (重影)

余晖的来源:

1、如果现在正在第0号数码管上显示数字‘E‘(‘E‘的段码是0x79),然后切换到第1号数码管上去显示数字‘1‘,中间不先将第0号数码管熄灭。

其过程是:修改位码、从第0号数码管切换到第1号数码管,修改段码、将段码由‘E‘的段码0x79改为‘1‘的段码0x06

切换到第1号数码管只修改了位码,此时的段码依然是‘E‘的段码0x79,此时第1号数码管就会显示数字‘E‘

接着把段码改为‘1‘的段码0x06,此时、第1号数码管才显示数字‘1‘

结果是、第1号数码管会先显示一小段时间(几个时钟周期)的数字‘E‘、然后才显示数字‘1‘(1ms)

显示数字‘1‘的时候、只有段[b,c]被点亮。

显示数字‘E‘的时候、只有段[a,d,e,f,g]会被点亮。

所以、第1号数码管显示数字‘1‘之前,段[a,d,e,f,g]会被点亮一段时间,然后才去点亮段[b,c],这里有一先一后的顺序。

但对于眼睛来说,由于时间太短,眼睛会认为显示几个时钟周期的数字‘E‘和显示1ms数字‘1‘是同时发生的。

看的的结果就是、第1号数码管显示数字‘1‘的时候、其他的段[a,d,e,f,g]是微亮的,这就是余晖

显示数字‘E‘的时间越久、第1号数码管来自第0号数码管的余晖就越明显。

另外、驱动电流越大,数码管越量,余晖也会越亮。

2、上面先修改位选、再修改段选。

如果先修改段选、再修改位选、一样会有余晖产生,如果不先熄灭数码管、让段码为0x00的话。

只是、第1号数码管的余晖来自第2号数码管,而不是第0号数码管。

因为数码管还没有从第1号切换到第2号之前,段码要先改成了第2号数码管要显示的段码。

3、所以在切换数码管之前,需要熄灭数码管,将段码先修改为熄灭显示的段码 0x00

4、或者、可以关闭数码管,也就是将所有数码管的com口都拉高,熄灭所有数码管。

在段码修改完毕后,再设置下一个数码管的位码,来使能下一个数码管。

上面的电路中、74HC138不能禁止所有数码管,所以只能使用熄灭显示的段码0x00

使用三极管控制数码管的com口的电路,可以禁止所有数码管。

测试代码:

说明:

1、如果屏蔽下面用于避免余晖的代码,就会有余晖。

2、但为了让余晖更明显,可以在切换到下一个数码管之前,延时几百微妙。

3、下面的代码使用#if 0来使能余晖的产生,并加入延时:

// ==========================================================================================================
//      LED数码管显示数据的刷新
//
// (1). 在系统定时器中每隔1ms刷新1次
//
// ==========================================================================================================
void Mod_LED_display_update(void)
{
#if 0
    // 熄灭当前数码管、并保持3个时钟周期的熄灭,用来避免余晖
    *p_LED_display_ctrl->seg_code = segment_code[sizeof(segment_code) - 1];
#endif

    // 切换到下1个数码管
    p_LED_display_ctrl->index++;
    if(p_LED_display_ctrl->index > (sizeof(segment_index) - 1))
    {
        p_LED_display_ctrl->index = 0;
    }

    // 修改位选、修改显示
    *p_LED_display_ctrl->seg_index |= segment_index[sizeof(segment_index) - 1];
    *p_LED_display_ctrl->seg_index &= segment_index[p_LED_display_ctrl->index];
    // 切换数码管后,延时一段时间,看看余晖,在修改段码
    for(volatile int j = 0; j < 20; j++) {}
    // 修改段码
    *p_LED_display_ctrl->seg_code   = segment_code[p_LED_display_ctrl->data[segment_index[p_LED_display_ctrl->index]]];
}

测试结果:

0、从左到右分别是第0号数码管到第7号数码管。

1、在第3号数码管上、可以明显的看到来自第2号数码管(显示数字‘0‘)的余晖。

第5、6、7号数码管上、也有明显的余晖。

2、第0号数码管上没有余晖,因为它的上一个数码管(第7号)显示的是数字‘1‘,其余晖被第0号数码管自己显示的数字‘0‘覆盖了。

同样的、第1、2、4号数码管上的余晖也是被覆盖了。

3、延时用的for循环中、有个volatile,用来避免编译器优化变量j

如果被优化掉,这段代码就没了,因为这段代码对AVR-GCC编译器来说、没有什么意义。

-------------------------------------------------------------------------------------------------------------------------------------

第五步: 改进后的代码

时间: 2024-12-16 00:18:57

B001-Atmega16-数码管的相关文章

AC620教程 第十五节 8位7段数码管驱动设计与验证

本章导读 电子系统中常用的显示设备有数码管.LCD液晶以及VGA显示器等.其中数码管又可分为段式显示(7段.米字型等)以及点阵显示(8*8.16*16等),LCD液晶的应用可以分为字符式液晶(1602.12864等)以及真彩液晶屏,VGA显示器一般是现在的电脑显示器.芯航线开发板对以上三种设备均提供了硬件接口. 本章将实现FPGA驱动数码管动态显示并提取出实现的电路结构,从电路结构入手编写代码,仿真对设计进行验证.最终板级调试时使用In system sources and probes edi

1225 八数码难题

1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.问题描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765

入侵某有限公司#并成功提下西部数码某虚拟主机

目标站点存在dede5.7通用的sql注入漏洞 利用工具  直接插入一个管理员 随后通过某大牛的爬虫工具获取到后台地址为 http://www.syguizaoni.com/gzhhoutai/index.php 登录 直接在功能表里的文件式管理器里面上传一个大马 大马地址: http://www.syguizaoni.com/uploads/php.php 密码:520 可以跨目录查看多个站群  便知道这个服务器是一个虚拟主机 然后上传一个小马  准备提权 http://www.syguiza

HDU 1043 Eight八数码解题思路(bfs+hash 打表 IDA* 等)

题目链接 https://vjudge.net/problem/HDU-1043 经典的八数码问题,学过算法的老哥都会拿它练搜索 题意: 给出每行一组的数据,每组数据代表3*3的八数码表,要求程序复原为初始状态 思路: 参加网站比赛时拿到此题目,因为之前写过八数码问题,心中暗喜,于是写出一套暴力bfs+hash,结果TLE呵呵 思路一:bfs+hash(TLE) 1 #include <cstdio> 2 #include <cstring> 3 #include <queu

洛谷【P1379】八数码难题

P1379 八数码难题 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变. 输入输出格式 输入格式: 输入初试状态,一行九个数字,空格用0表示 输出格式: 只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊

八数码三种用时差距极大的写法

进化史,一种比一种长,一种比一种快.不过第三种似乎还不是最终形态. 第一种,傻逼级迭代加深. 去年十一月写的,那时候刚刚学迭代加深,敲了一个钟头才敲完,codevs上直接过,就没太管,觉得这是个水题.实际上呢,看后文. 1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 using namespace std; 6 int sx,sy,lim,

八数码的八境界 [转载]

八数码的八境界   研究经典问题,空说不好,我们拿出一个实际的题目来演绎.八数码问题在北大在线测评系统中有一个对应的题,题目描述如下: Eight Time Limit: 1000MS    Memory Limit: 65536K  Special Judge Description The 15-puzzle has been aroundfor over 100 years; even if you don't know it by that name, you've seen it. I

树莓派控制数码管显示

1. 效果显示 2. 硬件设备 在某宝上买了一个4位共阴数码管.4个数字公用一个阴极,一共12个引脚.其中6,8,9,12是共阴引脚. 每个数字由 a-g 7个二极管和一个点dp.因为是在网上买的没有详细的器件手册,所以只能自己测试引脚与数码管上二极管的对应关系. 通过上图可以看出12号引脚对应的是第一位数字的共阴引脚,1号引脚对应数字e.依次测试,结果如下: 2.

(五)数码管仿真 02

电路图:注意 为了省事 把 数码管串联的电阻省去了 参考代码:  这里 检测按键并不好,抄的另外一篇日志,具体还要看书 #include<reg52.h> #include<intrins.h> #define uchar8 unsigned char #define uint16 unsigned int sbit key1=P2^0; sbit key2=P2^1; sbit key3=P2^2; sbit key4=P2^3; uchar8 code seg[]={ 0x3F

我的 FPGA 学习历程(10)&mdash;&mdash; 实验数码管驱动

根据黑金 AX301 手册,数码管位选信号命名为 SEL[5:0],其中 SEL[5] 对应最左边的数码管,而SEL[0] 对应最右边数码管:作为约定,在下面的描述中我们对应的称之为数码管 5 和数码管 0.数码管的段选信号被命名为 DIG[7:0]:DIG[7] 为小数点 DP,DIG[6] 为数码管 g 段,DIG[0] 为 a 段,其他类推即可. 由于数码管的段选信号是共用的,理论上是不可能同时显示六个不同字符的,但由于人眼的视觉残留现象,只要我们很快的依次显示每一个数字,就可以欺骗人眼达