CD74HCT574M灯环扫描

这个方案还是有点复杂的,需要好好记录下来,防止写完就忘,后面不好维护。

 理解这个灯环方案首先要了解574的工作原理。

我一开始看到电路图想当然的认为就是输入什么输出什么,其实也没错,但是!人家是寄存器!人家会一直保存着数据,即使没有片选,它里面的数据也是在的!

数据锁存和不锁存对灯环的驱动方案是完全不一样的。

 上表就是整个电路图的关系表。

GPIO1_11-14对应的就是LED_DRV0-3

灯环的每个灯珠上电就亮,下电就灭。因此需要高速刷新,防止其闪烁。

驱动步骤:

1.所有的574 CS拉低

2.所有DRV线拉低

3.向OUT_D口刷入数据,刷新顺序如上表的CS顺序。每刷一个芯片的数据,就拉高此芯片的CS脚,产生一个上升沿锁存数据

4.拉高DRV线,点亮此组的灯珠

具体代码如下:



///////////////////////////////////////////////////////////////////// 
// 
// 	led_scan():
//	func:灯环扫描刷新程序
//	input:
//	output:	
//
///////////////////////////////////////////////////////////////////// 
UINT32 ring_led_scan(UINT32 RET)
{
	UINT32 i,j,ret;

	//OC=0,74HCT574M寄存器输出数据
	GpioOutDataReset(GPIO_PORT1,BIT23|BIT24|BIT25|BIT26|BIT27);	

	//ROW全低,led灯环全部熄灭
	GpioOutDataReset(GPIO_PORT1,BIT11|BIT12|BIT13|BIT14);
	
	for(j=0;j<5; j++)//cs pin
	{		
		//led scan data set(col)
		for(i=0; i<8; i++)
		{		
			ret = i + j*32 + led_scan_row_pin_ptr*8;//led data ptr,灯环定位详见ASC51原理图分解
			
			if(ringled_data[ret])
			{
				GpioOutDataReset(GPIO_PORT1, led_data_scan_pin[i]);
			}
			else
			{
				GpioOutDataSetPlus(GPIO_PORT1, led_data_scan_pin[i]);
			}		
		}		

		//拉高CS,提供一个CLK上升沿。Clk上升沿将数据打入74HCT574M寄存器中锁存
		GpioOutDataSetPlus(GPIO_PORT1, led_cs_pin[j]);	

		if(ret==119 || ret==127)
		{
			break;
		}		
	}

	//拉高ROW,点亮此行的LED灯环
	GpioOutDataSetPlus(GPIO_PORT1, led_scan_row_pin[led_scan_row_pin_ptr++]);	

	if(4 == led_scan_row_pin_ptr)
	{
		led_scan_row_pin_ptr = 0;
	}
	
	return 0;
}

 ============================================================================================================================================================

新项目又采用了EXMC来刷新灯环:

  1 UINT32 led_scan_row_pin[4] = {GPIO_PIN_5,GPIO_PIN_12,GPIO_PIN_13,GPIO_PIN_14};
  2 UINT8 led_scan_row_pin_ptr=0;
  3 
  4 /******************************************************************************
  5 * EXMC控制rignLed是低电平有效,所以初始化为高
  6 * ring_led_data[0]是PAD0左8个灯环数据,     ring_led_data[1]是PAD0右7个灯环数据
  7   ring_led_data[2]是PAD1左8个灯环数据,     ring_led_data[3]是PAD1右7个灯环数据
  8   ring_led_data[4]是PAD2左8个灯环数据,     ring_led_data[5]是PAD2右7个灯环数据
  9   ring_led_data[6]是PAD3左8个灯环数据,     ring_led_data[7]是PAD3右7个灯环数据
 10   ring_led_data[8]是PAD4左8个灯环数据,     ring_led_data[9]是PAD4右7个灯环数据
 11   ring_led_data[10]是PAD5左8个灯环数据,    ring_led_data[11]是PAD5右7个灯环数据
 12   ring_led_data[12]是PAD6左8个灯环数据,    ring_led_data[13]是PAD6右7个灯环数据
 13   ring_led_data[14]是PAD7左8个灯环数据,    ring_led_data[15]是PAD7右7个灯环数据
 14   ring_led_data[16]是Balance左8个灯环数据, ring_led_data[17]是Balance右7个灯环数据
 15 * EXMC偏移的地址控制的旋钮灯如下:
 16     偏移4: 控制PAD2和PAD3
 17     偏移8: 控制PAD4和PAD5
 18     偏移16:控制PAD6和PAD7
 19     偏移32:控制balance
 20     偏移64:控制PAD0和PAD1
 21     基址偏移2没有控制PAD,但因为如果没有地址偏移2的数据写入,其余旋钮也无法控制,所以保留了此偏移地址
 22 ******************************************************************************/
 23 uint32_t ring_led_data[RING_LED_REAL_DATA_NUM] = {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
 24                                                   0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
 25 //EXMC控制地址偏移
 26 uint32_t ring_add_offset[6] = {2,4,8,16,32,64};
 27 
 28 
 29 /****************************************************************************
 30 *函数名:ring_led_io_init
 31 *输  入:无
 32 *输  出:无
 33 *功  能:初始化ringLED的IO口。
 34 ****************************************************************************/
 35 void RingLedIoInit()
 36 {
 37     unsigned int gpio = 0;
 38     //复用设置,复用为EXMC
 39     gpio_af_set(GPIOD, GPIO_AF_12, GPIO_PIN_0);
 40     gpio_af_set(GPIOD, GPIO_AF_12, GPIO_PIN_1);    
 41     gpio_af_set(GPIOD, GPIO_AF_12, GPIO_PIN_14);
 42     gpio_af_set(GPIOD, GPIO_AF_12, GPIO_PIN_15);
 43 
 44     gpio_af_set(GPIOE, GPIO_AF_12, GPIO_PIN_7);
 45     gpio_af_set(GPIOE, GPIO_AF_12, GPIO_PIN_8);
 46     gpio_af_set(GPIOE, GPIO_AF_12, GPIO_PIN_9);
 47     gpio_af_set(GPIOE, GPIO_AF_12, GPIO_PIN_10);
 48     
 49     gpio_af_set(GPIOF, GPIO_AF_12, GPIO_PIN_0);
 50     gpio_af_set(GPIOF, GPIO_AF_12, GPIO_PIN_1);
 51     gpio_af_set(GPIOF, GPIO_AF_12, GPIO_PIN_2);
 52     gpio_af_set(GPIOF, GPIO_AF_12, GPIO_PIN_3);
 53     gpio_af_set(GPIOF, GPIO_AF_12, GPIO_PIN_4);
 54 
 55     
 56     //GPIOD
 57     gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_14|GPIO_PIN_15);
 58     gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_14|GPIO_PIN_15);
 59 
 60     //GPIOE
 61     gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10);
 62     gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10);
 63 
 64     //GPIOF
 65     gpio_mode_set(GPIOF, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4);
 66     gpio_output_options_set(GPIOF, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4);
 67 
 68     gpio = GPIO_PIN_5|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14;
 69     gpio_mode_set(GPIOF, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, gpio);
 70     gpio_output_options_set(GPIOF, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, gpio);
 71     gpio_bit_reset(GPIOF, gpio);
 72     
 73     //拉低ROW
 74     gpio_bit_reset(GPIOF,GPIO_PIN_5|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14);
 75 }
 76 
 77 
 78 void RingledExmcInit(void)
 79 {
 80     exmc_norsram_parameter_struct  nor_init_struct;
 81     exmc_norsram_timing_parameter_struct  sram_timing_read;
 82     exmc_norsram_timing_parameter_struct  sram_timing_write;
 83     exmc_norsram_parameter_struct EXMC_NORSRAM_STRUCT;
 84     exmc_norsram_timing_parameter_struct READ_WRITE_TIMING_STRUCT; 
 85 
 86     READ_WRITE_TIMING_STRUCT.asyn_address_setuptime = 6;//6
 87     READ_WRITE_TIMING_STRUCT.asyn_address_holdtime =6;
 88     READ_WRITE_TIMING_STRUCT.asyn_data_setuptime = 6;    //5
 89     READ_WRITE_TIMING_STRUCT.syn_data_latency = EXMC_DATALAT_2_CLK;//SNTCFG_DLAT(syn_data_latency);;
 90     READ_WRITE_TIMING_STRUCT.bus_latency = 2;    //2
 91     READ_WRITE_TIMING_STRUCT.syn_clk_division = EXMC_SYN_CLOCK_RATIO_2_CLK;//SNTCFG_CKDIV(syn_clk_division);    //1
 92     READ_WRITE_TIMING_STRUCT.asyn_access_mode = EXMC_ACCESS_MODE_A;//SNTCFG_ASYNCMOD(asyn_access_mode);//EXMC_ACCESS_MODE_B
 93 
 94     EXMC_NORSRAM_STRUCT.norsram_region     = EXMC_BANK0_NORSRAM_REGION0;
 95     EXMC_NORSRAM_STRUCT.memory_type        = EXMC_MEMORY_TYPE_SRAM;
 96     EXMC_NORSRAM_STRUCT.databus_width    = EXMC_NAND_DATABUS_WIDTH_16B;
 97     EXMC_NORSRAM_STRUCT.wrap_burst_mode    = DISABLE;
 98     EXMC_NORSRAM_STRUCT.nwait_polarity    = EXMC_NWAIT_POLARITY_LOW;
 99     EXMC_NORSRAM_STRUCT.burst_mode        = DISABLE;    
100     EXMC_NORSRAM_STRUCT.nwait_config    = EXMC_NWAIT_CONFIG_BEFORE;
101     EXMC_NORSRAM_STRUCT.nwait_signal    = DISABLE;
102     EXMC_NORSRAM_STRUCT.memory_write    = ENABLE;
103     EXMC_NORSRAM_STRUCT.asyn_wait        = DISABLE;
104     EXMC_NORSRAM_STRUCT.write_mode        = EXMC_ASYN_WRITE;
105     EXMC_NORSRAM_STRUCT.extended_mode    = DISABLE;
106     EXMC_NORSRAM_STRUCT.address_data_mux= DISABLE;
107     EXMC_NORSRAM_STRUCT.read_write_timing= &READ_WRITE_TIMING_STRUCT;
108     EXMC_NORSRAM_STRUCT.write_timing    = &READ_WRITE_TIMING_STRUCT;
109     
110     exmc_norsram_init(&EXMC_NORSRAM_STRUCT);
111     exmc_norsram_enable(EXMC_BANK0_NORSRAM_REGION0);
112 }
113 
114 void RingLedExmcScan(void)
115 {    
116     UINT32 i,j,ret;
117     
118     //ROW全低,led灯环全部熄灭
119     gpio_bit_reset(GPIOF,GPIO_PIN_5|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14);
120 
121     //delay_us(10);
122 
123     if(led_scan_row_pin_ptr==0)
124     {
125         //PAD0、PAD2、PAD4、PAD6、balance左灯环数据刷新
126         *((uint32_t*)(0x60000000 + ring_add_offset[0])) = ring_led_data[0];  //未使用
127         *((uint32_t*)(0x60000000 + ring_add_offset[1])) = ring_led_data[4];  //PAD3
128         *((uint32_t*)(0x60000000 + ring_add_offset[2])) = ring_led_data[8];  //PAD5
129         *((uint32_t*)(0x60000000 + ring_add_offset[3])) = ring_led_data[12]; //PAD7
130         *((uint32_t*)(0x60000000 + ring_add_offset[4])) = ring_led_data[16]; //banlcnce
131         *((uint32_t*)(0x60000000 + ring_add_offset[5])) = ring_led_data[0];  //PAD1
132     }
133     else if(led_scan_row_pin_ptr==1)
134     {
135         
136         //PAD0、PAD2、PAD4、PAD6、balance右灯环数据刷新
137         *((uint32_t*)(0x60000000 + ring_add_offset[0])) = ring_led_data[0];  //未使用
138         *((uint32_t*)(0x60000000 + ring_add_offset[1])) = ring_led_data[5];  //PAD3
139         *((uint32_t*)(0x60000000 + ring_add_offset[2])) = ring_led_data[9];  //PAD5
140         *((uint32_t*)(0x60000000 + ring_add_offset[3])) = ring_led_data[13]; //PAD7
141         *((uint32_t*)(0x60000000 + ring_add_offset[4])) = ring_led_data[17]; //banlcnce
142         *((uint32_t*)(0x60000000 + ring_add_offset[5])) = ring_led_data[1];  //PAD1
143     }
144     if(led_scan_row_pin_ptr==2)
145     {
146 
147         //PAD1、PAD3、PAD5、PAD7左灯环数据刷新
148         *((uint32_t*)(0x60000000 + ring_add_offset[0])) = ring_led_data[0]; //未使用
149         *((uint32_t*)(0x60000000 + ring_add_offset[1])) = ring_led_data[6]; //PAD4
150         *((uint32_t*)(0x60000000 + ring_add_offset[2])) = ring_led_data[10];//PAD6
151         *((uint32_t*)(0x60000000 + ring_add_offset[3])) = ring_led_data[14];//PAD8
152         *((uint32_t*)(0x60000000 + ring_add_offset[4])) = ring_led_data[2]; //未使用
153         *((uint32_t*)(0x60000000 + ring_add_offset[5])) = ring_led_data[2]; //PAD2
154     }
155     else if(led_scan_row_pin_ptr==3)
156     {
157         //PAD1、PAD3、PAD5、PAD7右灯环数据刷新
158         *((uint32_t*)(0x60000000 + ring_add_offset[0])) = ring_led_data[0]; //未使用
159         *((uint32_t*)(0x60000000 + ring_add_offset[1])) = ring_led_data[7]; //PAD4
160         *((uint32_t*)(0x60000000 + ring_add_offset[2])) = ring_led_data[11];//PAD6
161         *((uint32_t*)(0x60000000 + ring_add_offset[3])) = ring_led_data[15];//PAD8
162         *((uint32_t*)(0x60000000 + ring_add_offset[4])) = ring_led_data[3]; //未使用
163         *((uint32_t*)(0x60000000 + ring_add_offset[5])) = ring_led_data[3]; //PAD2
164     }
165 
166     //拉高ROW,点亮此行的LED灯环
167     gpio_bit_set(GPIOF, led_scan_row_pin[led_scan_row_pin_ptr++]);    
168 
169     //delay_us(10);
170     
171     if(4 == led_scan_row_pin_ptr)
172     {
173         led_scan_row_pin_ptr = 0;
174     }
175 
176     return;
177 
178 }
179 
180 void RingLedInit(void)
181 {
182       RingLedIoInit();
183     RingledExmcInit();
184 }

 这个方案存在一个问题。那就是灯环会影响周边的灯环。比如旋转灯环1,灯环2的右侧灯珠会被点亮,很微弱的亮度。

猜测可能就是灯环1的数据的某些bit被刷到灯环2上去了。

然后解决方法也很简单,就是增加延时。如121和169行。

还有个问题就是他们写这个代码的时候,把

RingLedExmcScan
放到中断里执行的。如果没有延时那放到中断里也无所谓,但是加了延时那就会严重影响中断的响应,进而影响到了数码管的刷新(数码管和灯环都在同一个中断执行函数里)
其实他们放到中断里也有我的锅,因为我一直没把release的优化打开,导致他们一直使用-O 0运行的代码。
那么如果把RingLedExmcScan放到任务里,就会导致灯环闪烁
把release开到-O fast + LTO,然后再把RingLedExmcScan放到任务里,灯环就不闪烁了
posted @ 2021-12-23 17:16  xjxcxjx  阅读(257)  评论(0)    收藏  举报