74HC595数码管驱动开发

这个数码管是个通用性数码管,网上资料很多,拿来直接套就行。

本项目是通过一个595芯片控制两个数码管的显示,Q7为1时左边的数码管显示,为0时右边的数码管显示

不需要初始化,直接把IO口初始化下即可。

/*GPIO输出引脚*/
    gpio = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15;//GPIO_PIN_13 | 
    gpio_mode_set(GPIOC, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, gpio);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, gpio);
 1 //74HC595口线定义宏定义.当驱动74HC595引脚改变时,只需更改底层引脚宏定义即可
 2 #define    LED595_DATA_PORT     GPIOC
 3 #define    LED595_DATA_PIN      GPIO_PIN_9
 4 #define    LED595_CLK_PORT      GPIOC
 5 #define    LED595_CLK_PIN       GPIO_PIN_8
 6 #define    LED595_LATCH_PORT    GPIOC
 7 #define    LED595_LATCH_PIN     GPIO_PIN_10
 8 //74HC595口线高低电平宏定义
 9 #define    LED595_DATA_SET      gpio_bit_set(LED595_DATA_PORT,LED595_DATA_PIN)
10 #define    LED595_DATA_RESET    gpio_bit_reset(LED595_DATA_PORT,LED595_DATA_PIN)
11 #define    LED595_CLK_SET       gpio_bit_set(LED595_CLK_PORT,LED595_CLK_PIN)
12 #define    LED595_CLK_RESET     gpio_bit_reset(LED595_CLK_PORT,LED595_CLK_PIN)
13 #define    LED595_LATCH_SET     gpio_bit_set(LED595_LATCH_PORT,LED595_LATCH_PIN)
14 #define    LED595_LATCH_RESET   gpio_bit_reset(LED595_LATCH_PORT,LED595_LATCH_PIN)
 1                 /*LED数码管显示        0     1    2   3     4      5        6    7    8      9    */
 2 UINT8 led595displaycode[2][10] = {{0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF},//LEFT
 3                                   {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F} //RIGHT
 4                                   };
 5 
 6 BOOLEAN led595_flush_flag = FALSE;//数码管左右轮流显示
 7 
 8 UINT8 led595_display_temp=0xff; 
 9 UINT8 led595_display_buf[2]; //存放数码管左右显示的数据
10 
11 
12 
13 /**
14  *74HC595输出锁存 使能 
15 **/
16 void HC595_CS(void) 
17 {
18     /**  步骤3:STCP产生一个上升沿,移位寄存器的数据移入存储寄存器  **/
19     LED595_LATCH_RESET;   // 将STCP拉低
20     delay_1us(1);           // 适当延时
21     LED595_LATCH_SET;  // 再将STCP拉高,STCP即可产生一个上升沿
22     delay_1us(1);
23 }
24 
25 /**
26   * @brief  将输入的数据输出到74HC595的引脚.
27   * @param  Input 1 byte data.
28   * @retval None.
29 **/
30 void HAL_LED595SendData(UINT8 OutData)
31 {
32     UINT8 i; //发送数据时做循环使用临时变量
33     for(i=0; i<8; i++) //将8位数据按位发送,先发送高字节后发送低字节
34     {
35         LED595_CLK_RESET;//时钟线低电平       
36         
37         if( (OutData & 0x80) == 0x80)//判断数据高低位
38         {
39             LED595_DATA_SET;                   //数据线高电平
40         }
41         else
42         {
43              LED595_DATA_RESET;          //数据线低电平
44         }
45         OutData = OutData << 1;         //数据左移1位
46         
47         LED595_CLK_SET;                 //时钟线高电平    
48     }
49 
50     HC595_CS();//先把所有字节发送完,再使能输出    
51 }
52 
53 //用户接口函数,提供用于数码管显示的接口
54 void LED595_dispaly(UINT8 Data)
55 {    
56     if(led595_display_temp != Data)
57     {
58         led595_display_temp = Data;
59 
60         if(led595_display_temp<10)
61         {
62             led595_display_buf[0] = led595displaycode[0][0];
63             led595_display_buf[1] = led595displaycode[1][led595_display_temp];
64         }
65         else
66         {
67             led595_display_buf[0] = led595displaycode[0][led595_display_temp/10];
68             led595_display_buf[1] = led595displaycode[1][led595_display_temp%10];
69         }
70     }
71 }
72 
73 //用于数码管的中断刷新显示
74 void led595_displayPro(void)
75 {
76     if(led595_flush_flag)
77     {
78         HAL_LED595SendData(led595_display_buf[0]);
79     }
80     else
81     {
82         HAL_LED595SendData(led595_display_buf[1]);        
83     }
84 
85     led595_flush_flag = !led595_flush_flag;
86 }
因为数码管是左右两个轮流刷的,刷其中一个的时候另一个会熄灭,需要将 led595_displayPro()函数放在10ms的中断中进行高速刷新。10ms看起来很稳定,不会有闪烁的现象

==========================================================================================================================================
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
重新看了下数据手册,感觉以前的驱动还是不太好。

 这里可以看到,CLK_RESET紧接着就是 DATA_SET, 然后就是CLK_SET.

这里没有延时,CLK和DATA的保持时间全靠芯片的运行间隙。这也是为啥这个驱动没法开优化的原因。

因此需要添加延时

 1 //用于数码管的中断刷新显示
 2 void led595_displayPro( void )
 3 {
 4     led595_flush_flag = !led595_flush_flag;
 5 
 6     LED595_CS1_RESET();
 7     LED595_CS2_RESET();
 8 
 9     delay_us(HC595_DELAY_CNT);
10 
11     HAL_LED595SendData( led595_display_buf[led595_flush_flag] );
12 
13     if ( led595_flush_flag )
14     {
15         LED595_CS2_SET();
16     }
17     else
18     {
19         LED595_CS1_SET();
20     }
21     delay_us(HC595_DELAY_CNT);
22 
23     return;
24 }
25 
26 
27 void HAL_LED595SendData( UINT16 OutData )
28 {
29     for ( UINT8 i = 0; i < 8; i++ )                //将8位数据按位发送,先发送高字节后发送低字节
30     {
31         if ( ( OutData & ( 1 << ( 7 - i ) ) ) )//判断数据高低位
32         {
33             LED595_DATA_SET;             //数据线高电平
34         }
35         else
36         {
37             LED595_DATA_RESET;          //数据线低电平
38         }
39 
40         LED595_CLK_SET;                  //时钟线高电平
41         delay_us(HC595_DELAY_CNT); 
42         LED595_CLK_RESET;//时钟线低电平
43         delay_us(HC595_DELAY_CNT); 
44     }
45 
46     HC595_CS();//锁存
47 
48     return;
49 }

这样修改后其波形稳定,然后

1、将工程的优化打开至 -O fast + LTO,

2、将 led595_displayPro 放置到task里执行

发现数码管还是无法正常刷新。

然后将数码管文件单独降低优化至 -O 1, 数码管工作正常

至此,先出个能稳定工作的版本。后续有时间再探究下为什么数码管还是优化敏感。猜测还是跟时间相关。

 







posted @ 2021-12-14 18:18  xjxcxjx  阅读(932)  评论(0)    收藏  举报