2010-II/es/2010Digital2

From Qi-Hardware
Jump to: navigation, search

ANALIZADOR DE ESPECTRO DE AUDIO


Contents

[edit] Calificación

Porcentaje Presentación 20% Informe 30% Funcionamiento 50%
1 Entrega 10% 0.5 0.5 0.5
2 Entrega 30% 1.7 1.7 1.7
3 Entrega 20% 3 4 3
4 Entrega 40% 4.5 4.5 4.5


Es en esencia un dispositivo que a partir de una entrada de audio toma diferentes rangos de frecuencias, los separa y exhibe su intensidad en un gráfico como el que muestran varios reproductores de computador; existen tanto análogos como digitales, en este caso desarrollaremos un analizador digital.

Para implementarlo utilizaremos un proceso matemático llamado Transformada Rapida de Fourier (FFT), por medio del cual se transforma un señal continua (como el audio) en los diversos componentes de su espectro en frecuencia; este análisis se visualizara en el display gráfico del SIE, cuya interfaz mostrara 3 canales incluyendo la frecuencia máxima.

Cuando se habla de separar en canales se trata de dividir el espectro de frecuencias en varios rangos de frecuencias ya que en realidad eso es lo que obtenemos del filtro.



[edit] ESPECIFICACIONES

Físicas

El proyecto se implementara en la tarjeta de desarrollo SIE, con la ayuda de una tarjeta hija que contiene la matriz de leds (con su correpondiente amplificación), la memoria y el circuito análogo cambiador de nivel, las dimensiones de las tarjetas hijas es de 9cm x 8.1cm que es mismo tamaño que el sie.

Funcionales

Diagrama de Flujo

Diagrama de flujo del analizador de espectro de audio

[edit] PARTICIONAMIENTO

[edit] Diagrama de bloques

Diagrama del bloques del analizador de espectro de audio
Wb.png

[edit] Mapa de Memoria

Periferico Dirección
BRAM 15'h0000
UART 15'h7000
Timer 15'h7001
GPIO 15'h7002
Uniont 15'h7003

[edit] Circuitos implementados

La siguiente galería muestra el diseño de la PCB que vamos a utilizar en este proyecto:

[edit] Cambio de Nivel

Se refiere a montar la señal de audio en una señal DC. Vamos a utilizar una señal de audio de salida del computador. Esta señal se encuentra alrededor de 2 voltios pico a pico, y la idea sería montarla en una de 1 voltio DC para poder tener los datos en un rango de 0 y 2 voltios.

Circuito cambiador de nivel

[edit] Matriz de Leds

esta parte se refiere a la comunicación con la matriz de leds para graficar la frecuencia contra ganancia de la señal de audio; para el desarrollo del PCB se debe tener en cuenta los requerimientos de corriente y potencia propios de la matriz, así como también la configuración de la matriz, en este caso usaremos una matriz de 5x7 (5 Columnas - 7 Filas) con los ánodos ubicados en las columnas y los cátodos ubicados en las filas.

El circuito de la matriz de leds consta de varios amplificadores, para las columnas se utilizaron transistores tipo PNP, con una resistencia de 1k ohmios en la base y otra resistencia de 100 ohmios en el emisor. Al colector se le conectó una fuente de 3.3 voltios, que corresponde al pin numero 27 del sie; a la base se conectaron las correspondientes salidas digitales del sie.

Para las filas se utilizó un arreglo de amplificadores de tipo Darlington que corresponden al circuito integrado ULN2803, los cuales van conectados de la siguiente manera: las bases de los transistores van conectadas a una fuente de 3.3 voltios que corresponde al pin 27 del sie, y los colectores van a las salidas digitales del sie y a las filas del la matriz de leds.


[edit] Hardware

[edit] ADC

Básicamente en esta etapa lo que se hace es discretizar la señal de entrada. El ADC con el que vamos a trabajar es el que viene integrado con la tarjeta SIE que es el de referencia TLV1548C. Este ADC es serial, de 10 bits, con 8 canales de entrada análogas, con tiempo de conversión de 10us y frecuencia de muestreo es de 10kHz.


  * 0x00: En el cambio de nivel de alto a bajo de ~CS, se habilitan las señales DATA_IN, DATA_OUT y I/O CLK. Mientras se recibe
    DATA_IN; DATA_OUT está transmitiendo los datos de la anterior conversión al Wishbone. 
  * 0x04: EOC pasa de nivel alto a bajo cuando se completa el décimo ciclo de reloj, que es cuando se termina el muestreo y
    comienza la conversión, y luego pasa a alto cuando se ha completado la conversión y ~CS pasa a nivel alto de nuevo.         

Descripción de funcionamiento del periferico hardware: En los primeros 4 ciclos de reloj después que se ha puesto ~CS en nivel bajo, se lee la señal de entrada DATA_IN y se transmiten los datos de la señal DATA_OUT de la conversión anterior; los siguientes 6 ciclos de reloj proveen el control de tiempo para muestrear la señal análoga que se ha escogido con la señal DATA_IN. En ese momento ya se completan 10 ciclos de reloj, momento en el cual se pone EOC en 0 y comienza la conversión. EOC vuelve a 1 cuando se completa la conversión y ~CS puede volver a se 1. En este momento el proceso vuelve a empezar cuando se ponga de nuevo ~CS en nivel bajo.

Diagrama de flujo del ADC
Data Path


El primer paso a realizar para comenzar a usar el ADC es inicializarlo, para ello debemos enviarle datos específicos en la entrada ADC_DIN. Lista completa de comandos que recibe el ADC:

Tabla de Comandos

Para el correcto funcionamiento del ADC se debe seguir cierta secuencia de tiempos, para ellos observamos la siguiente imagen:

Secuencia de tiempo ADC

Para poder manejar el ADC es necesario manejar la siguiente interfez:

  • Interfaz Serial (SPI): es un estándar de comunicación que utiliza un bus de 4 líneas para interconectar dispositivos periféricos de baja y media velocidad, la comunicación se realiza siguiendo un modelo maestro/esclavo donde el maestro selecciona al esclavo y comienza el proceso de transmisión/recepción de información; SPI constituye un bus full duplex, es decir, que se puede enviar y recibir información de manera simultánea, lo cual, eleva la tasa de transferencia de los datos.
Esquema de Comunicación SPI

Los nombres de las señales son definidos dentro del estándar como:

  * SCLK (reloj del bus) 
  * MOSI (Master Output Slave Input): salida de datos del maestro y entrada de datos a los esclavos
  * MISO (Master Input Slave Output): salida de datos de los esclavos y entrada de datos al maestro
  * SS (Slave Select): habilitación del esclavo por parte del maestro


  • Código en Verilog del ADC
  1. module SPI_slave_ADC(
  2. 	input 		clk,
  3. 	input 		reset, 
  4. 	input 		start,
  5. 	output wire 	miso,
  6. 	output wire 	led,
  7. 	output wire 	led2,
  8. 	output reg      flagmem,
  9. 	input 		[3:0] datain,
  10.  
  11. // ADC
  12. 	input 		ADC_DOUT,
  13. 	input 		ADC_EOC,
  14. 	output reg	ADC_SCLK,
  15. 	output reg	ADC_CS,
  16. 	output reg 	ADC_DIN,
  17. 	output wire 	ADC_CSTART
  18. );
  19.  
  20.  
  21. parameter count_c=17'd100000; //Counts 10us
  22.  
  23. reg 	miso_r;
  24. reg     [4:0] temp;
  25. reg     [16:0] temp_1;
  26. reg     [3:0] buffer_in;
  27. reg     [4:0] pulsos;
  28. reg     [2:0] state,next_state;
  29. reg     bajoSCLK=0;
  30. reg     altoSCLK=0;
  31. reg     [8:0] counter;
  32. reg     buff_start;
  33. reg     init;
  34.  
  35.  
  36. initial begin
  37.   temp=0;
  38.   temp_1=0;
  39.   ADC_CS=1;
  40.   ADC_DIN=1'b0;
  41.   miso_r=1'd0;
  42.   buffer_in=4'd0;
  43.   pulsos=4'd0;
  44.   state=3'd0;
  45.   next_state=3'd0;
  46.   counter=9'd0;
  47.   ADC_SCLK=1'd0;
  48.   buff_start=1'd0;
  49.   init=1'd0;
  50.   ADC_CSTART=1;
  51. end	 
  52.  
  53. //datain=4'b1011 ---> la salida es 10'b1000000000
  54. //conversión Rápida ----> ADC_DIN=4'b1001
  55.  
  56. always@(posedge clk)
  57. begin
  58. 	if(~start)	buff_start=1'd1;
  59. 	if(reset)
  60. 	begin
  61. 		buff_start=1'd0;
  62. 		ADC_DIN=1'b0;
  63. 		miso_r=1'd0;
  64. 		buffer_in=4'd0;
  65. 		pulsos=4'd0;
  66. 		state=3'd0;
  67. 		next_state=3'd0;
  68. 		counter=9'd0;
  69. 		ADC_SCLK=1'd0;
  70. 		init=1'd0;
  71. 	end
  72.  
  73. 	if(buff_start)
  74. 	begin
  75. 	if(counter<9'd500) 
  76. 	begin
  77. 		counter=counter+1'd1;	
  78. 	end
  79. 	else if (counter==9'd500)
  80. 	begin
  81. 		pulsos=pulsos+1'd1;
  82. 		counter=9'd0;
  83. 		ADC_SCLK=~ADC_SCLK;
  84. 	end
  85.  
  86. 	state=next_state;
  87.  
  88. 	case(state)
  89. 		3'd0:begin
  90. 			if(ADC_EOC==1'd1 && init==1'd0) 
  91. 			begin			
  92. 				ADC_CS=1'd0;
  93. 				next_state=3'd1;
  94. 				buffer_in=4'b1001;
  95. 			end
  96. 			else if(ADC_EOC==1'd1 && init==1'd1) 
  97. 			begin			
  98. 				ADC_CS=1'd0;
  99. 				next_state=3'd2;
  100. 				buffer_in=datain;
  101.  
  102. 			end
  103. 		end
  104. 		3'd1:begin
  105. 			if(ADC_SCLK==1'd0 && counter==9'd250)
  106. 			begin
  107.  
  108. 				miso_r=ADC_DOUT;
  109. 				flagmem<=1'b0;
  110. 				if(ADC_SCLK==1'd0 && pulsos<=5'd8)
  111. 			begin
  112. 				ADC_DIN=buffer_in[3];
  113. 				buffer_in = buffer_in << 1;
  114. 			end
  115. 			end
  116. 			else if (pulsos>5'd20)
  117. 			begin
  118. 				next_state=3'd3;
  119.  
  120. 				init=1'd1;
  121. 				flagmem<=1'b0;
  122. 			end
  123. 		end
  124. 		3'd2:begin
  125. 			if(ADC_SCLK==1'd0 && counter==9'd250)
  126. 			begin
  127.  
  128. 				miso_r=ADC_DOUT;
  129. 				flagmem<=1'b1;
  130. 			        if(ADC_SCLK==1'd0 && pulsos<=5'd8)
  131. 			begin
  132.  
  133. 				ADC_DIN=buffer_in[3];
  134. 				buffer_in = buffer_in << 1;
  135. 			end
  136. 			end
  137. 			else if (pulsos>5'd20)
  138. 			begin
  139. 				next_state=3'd3;
  140. 				flagmem<=1'b0;
  141.  
  142. 			end
  143. 		end
  144. 		3'd3:begin
  145. 			if (ADC_EOC==1'd0)
  146. 			begin
  147. 				pulsos=4'd0;
  148. 			end
  149. 			else if (ADC_EOC==1'd1 && pulsos==4'd0)
  150. 			begin
  151. 				ADC_CS=1'd1;
  152. 			end
  153. 			if(ADC_CS==1'd1 && pulsos==4'd7)
  154. 			begin
  155. 				next_state=3'd0;
  156. 				pulsos=4'd0;
  157. 			end
  158. 		end
  159.  
  160. 	endcase
  161.  
  162.  
  163. 	end
  164. end
  165. assign miso=miso_r;
  166. endmodule
  • Diagramas RTL
Diagrama RTL general del ADC
Diagrama RTL interno del ADC


  • Simulación

Luego de realizar el código en Verilog se obtuvo la siguiente simulación, en donde se observan los valores de inicialización (1001 ---> Conversión Rápida), el ciclo de conversión que es de 10us (para efectos de simulación se uso un tiempo de 40ns) y el cambio de las señales de control propias del ADC, en este punto ahí que aclarar que algunas variables, como ADC_EOC (que se le asigna a la señal wb_dat_o) las genera el ADC físico, por lo tanto en la simulación no van a presentar ningún cambio. Además se ha asignado que la señal ADC_CS sea la quinta posición del arreglo wb_dat_i y que la entrada ADC_DIN sea las posiciones [3:0] de wb_dat_i. También para efectos de simulación se colocó la dirección 0 para el arreglo wb_adr_i.

Simulación del adc sin wb
  • Prueba

La anterior foto nos muestra el correcto funcionamiento del ADC del SIE. En esta se puede observar la señal EOC que nos que se mantiene en 1 mientras se muestrean los datos, se pone en 0 cuando se realiza la conversión y luego vuelve a 1 cuando se ha realizado el fin de la conversión.

Prueba en el laboratorio
Prueba en el laboratorio

En la anterior foto se logra ver en la parte superior la señal ADC_DOUT, con esto podemos comprobar que realmente se esta recibiendo la señal de audio digitalizada. Además en la parte inferior se esta mostrando la señal ADC_EOC que indica el tiempo de conversión.

[edit] Memoria

La idea principalmente es guardar en una pila los datos que provienen del ADC, para luego poder procesarlos en el módulo de FFT y asi poder visualizar en tiempo real en los leds. Para realizar esto se tienen dos opciones, la primera es hacer uso de los bloques de RAM disponibles en la fpga, con lo cual contamos con 360K de memoria, pero este espacio esta sujeto a disponibilidad dependiendo cuanto espacio ocupe el procesador y el programa como tal; por esta razón, la opción 2 es usar un SRAM externa de 32K.

Diagrama flujo memoria
  • Opción 1
Distribución BRAM en FPGA
  1. module memoria #(
  2. parameter mem_file_name = ("none")
  3. )(
  4. input clk,
  5. input ADC_SCLK,
  6. input miso,
  7. input flagmem,
  8. input reset,
  9. input start,
  10. output reg [9:0]infft0,
  11. output reg [9:0]infft1,
  12. output reg [9:0]infft2,
  13. output reg [9:0]infft3,
  14. output reg [9:0]infft4,
  15. output reg [9:0]infft5,
  16. output reg [9:0]infft6,
  17. output reg [9:0]infft7
  18. );
  19.  
  20. reg  [9:0]mem[63:0];
  21. reg [3:0]count10;
  22. reg [6:0]count64;
  23. reg [9:0]infft_r0;
  24. reg [9:0]infft_r1;
  25. reg [9:0]infft_r2;
  26. reg [9:0]infft_r3;
  27. reg [9:0]infft_r4;
  28. reg [9:0]infft_r5;
  29. reg [9:0]infft_r6;
  30. reg [9:0]infft_r7;
  31. reg [9:0]memtemporal;
  32. reg bajoSCLK=0;
  33. reg altoSCLK=0;
  34. reg [2:0] countmemoria;
  35. reg reset_pass;
  36. reg pass;
  37. reg buff_start;
  38. wire [9:0] buff_dout;
  39. reg [3:0] count_fft;
  40. reg [14:0] counter;
  41. reg clk_frec;
  42.  
  43. initial 
  44. begin
  45.     count10=4'd10;
  46.     count64=7'b0;
  47.     countmemoria=4'd1;
  48.     reset_pass=0;
  49.     count_fft=0;
  50.     infft_r0=0;
  51.     infft_r1=0;
  52.     infft_r2=0;
  53.     infft_r3=0;
  54.     infft_r4=0;
  55.     infft_r5=0;
  56.     infft_r6=0;
  57.     infft_r7=0;
  58.     counter=0;
  59.     clk_frec=0;
  60. end
  61.  
  62. reg [5:0] addr;
  63. wire [5:0] addr_1;
  64.  
  65. memoria_ram #(
  66. .mem_file_name(mem_file_name)
  67. )
  68. memoria_m (
  69.     .clk(clk), 
  70.     .we(we), 
  71.     .addr(addr_1), 
  72.     .din(din), 
  73.     .dout(buff_dout)
  74.     );
  75.  
  76. initial begin
  77. 	addr=0;
  78. end
  79.  
  80. // Este código usa una memoria inicializada a traves de un archivo .ram
  81.  
  82. always@(posedge clk)
  83. begin
  84. 	if(reset) 
  85. 	begin
  86. 		buff_start=1'd0;
  87. 		count_fft=0;
  88. 		infft_r0=0;
  89. 		infft_r1=0;
  90. 		infft_r2=0;
  91. 		infft_r3=0;
  92. 		infft_r4=0;
  93. 		infft_r5=0;
  94. 		infft_r6=0;
  95. 		infft_r7=0;
  96. 		pass=0;
  97. 		infft0=0;
  98. 		infft1=0;
  99. 		infft2=0;
  100. 		infft3=0;
  101. 		infft4=0;
  102. 		infft5=0;
  103. 		infft6=0;
  104. 		infft7=0;
  105. 		counter=0;
  106. 		clk_frec=0;
  107. 	end
  108. 	if(~start) buff_start=1'd1;
  109. 	if(buff_start)
  110. 	begin
  111. 		if(counter<15'd15000) 
  112. 		begin
  113. 			counter=counter+1'd1;	
  114. 			clk_frec=0;
  115. 		end
  116. 		else if (counter==15'd15000)
  117. 		begin
  118. 			clk_frec=1;
  119. 			counter=15'd0;
  120. 		end
  121. 		if(clk_frec)
  122. 		begin
  123. 			if(addr==64)
  124. 			begin 
  125. 				addr=0;  
  126. 			end
  127. 			else addr=addr+1;
  128.  
  129. 			if(count_fft<=7)
  130. 			begin
  131. 				case(count_fft)
  132. 					4'd0: begin infft_r0=buff_dout; count_fft=1; pass=0; end
  133. 					4'd1: begin infft_r1=buff_dout; count_fft=2; end
  134. 					4'd2: begin infft_r2=buff_dout; count_fft=3; end
  135. 					4'd3: begin infft_r3=buff_dout; count_fft=4; end
  136. 					4'd4: begin infft_r4=buff_dout; count_fft=5; end
  137. 					4'd5: begin infft_r5=buff_dout; count_fft=6; end
  138. 					4'd6: begin infft_r6=buff_dout; count_fft=7; end
  139. 					4'd7: begin infft_r7=buff_dout; count_fft=0; pass=1; end
  140. 					default: begin count_fft=0; pass=0; end
  141. 				endcase
  142. 			end
  143. 			if(pass) 
  144. 			begin
  145. 				count_fft=0;
  146. 				infft0=infft_r0;
  147. 				infft1=infft_r1;
  148. 				infft2=infft_r2;
  149. 				infft3=infft_r3;
  150. 				infft4=infft_r4;
  151. 				infft5=infft_r5;
  152. 				infft6=infft_r6;
  153. 				infft7=infft_r7;
  154. 			end
  155. 		end	
  156. 	end
  157. end
  158.  
  159. assign addr_1=addr;
  160.  
  161. //------------------------------------------------------------------------------------
  162.  
  163. // Este código llena una memoria a partir de las salidas del ADC
  164.  
  165. always@(ADC_SCLK)
  166. begin
  167. 	if(ADC_SCLK)
  168. 	begin
  169. 		bajoSCLK=0;
  170. 		altoSCLK=1;		
  171. 	end
  172. 	else begin
  173. 		bajoSCLK=1;
  174. 		altoSCLK=0;		
  175. 	end
  176. end
  177.  
  178.  
  179. always@(negedge clk)
  180. 	begin
  181. 	if(flagmem)
  182. 		begin
  183. 		memtemporal[count10]=miso;
  184. 		mem[count64]=memtemporal;
  185. 		end
  186. 	end
  187.  
  188. always@(posedge bajoSCLK)
  189. 	begin
  190. 		if(~start) begin 
  191. 				buff_start=1'd1; 
  192. 				count10=4'd10;
  193. 				count64=7'b0; 
  194. 				countmemoria=3'd0; 
  195. 			   end
  196. 		if(reset)
  197. 		begin
  198. 			count10=4'b0;
  199. 			count64=7'b0;	
  200. 			buff_start=1'd0;
  201. 			countmemoria=3'd0;
  202. 		end
  203.  
  204. 		if(buff_start)
  205. 		begin
  206. 		if(count10==4'b0)
  207. 			begin
  208. 			case(countmemoria)
  209. 					3'd1:infft_r0= begin mem[count64]; reset_pass=1'b0; end
  210. 					3'd2:infft_r1= mem[count64];
  211. 					3'd3:infft_r2= mem[count64];
  212. 					3'd4:infft_r3= mem[count64];
  213. 					3'd5:infft_r4= mem[count64];
  214. 					3'd6:infft_r5= mem[count64];
  215. 					3'd7:infft_r6= mem[count64];
  216. 					3'd0:infft_r7= mem[count64];
  217. 			default:reset_pass=1'b1;	
  218. 			endcase
  219.  
  220. 				if(countmemoria==3'd0)
  221. 					pass<=1'd1;
  222. 				else if(countmemoria!=3'd0)
  223. 					pass<=1'd0;
  224. 			end
  225.  
  226. 		if (flagmem)
  227. 		 begin		
  228. 			count10=count10-1'b1;
  229. 			if(count10==4'd15)
  230. 			 begin
  231. 			 	count64=count64+1'b1;
  232. 			 	count10=4'd9;
  233.  
  234. 				if(reset_pass)
  235. 				  countmemoria=0;
  236. 				else
  237. 				  countmemoria=countmemoria+1'b1;
  238.  
  239. 			 end
  240.  
  241. 			if(count64==7'd64)
  242. 		   	count64=7'b0;
  243. 		 end
  244.  
  245.  
  246.  
  247. 	if (pass==1'd1)	
  248. 	begin
  249. 		infft1=infft_r1;
  250. 		infft2=infft_r2;
  251. 		infft3=infft_r3;
  252. 		infft4=infft_r4;
  253. 		infft5=infft_r5;
  254. 		infft6=infft_r6;
  255. 		infft7=infft_r7;
  256. 		infft0=infft_r0;
  257. 	end
  258.  
  259. 	end	
  260. end
  261. endmodule

Del anterior código se puede ver que se ha hecho una pequeña memoria de 640 bits, en la cual almacenamos cada uno de los datos que nos entrega el ADC. En cada una de las filas de 10 bits se ha guardado un dato y todos estos posteriormente serán entregados al modulo de la FFT; esto se hace de manera paralela ya que es necesario entregarle 8 arreglos de 10 bits a la FFT.

Diagrama RTL simplificado
Diagrama RTL interior
Simulación de la memoria

Inicialización de la RAM de prueba

  1. module memoria_ram #(
  2. parameter mem_file_name = "none"
  3. )(
  4. input wire clk,
  5. input wire we,
  6. input wire [5:0] addr,
  7. input wire [9:0] din,
  8. output wire [9:0] dout
  9.  
  10. );
  11.  
  12.  
  13. // signal declaration
  14. reg [9:0] ram [0:63];
  15.  
  16. initial 
  17. begin
  18. 	if (mem_file_name != "none")
  19. 	begin
  20. 		$readmemb(mem_file_name, ram);
  21. 	end
  22. end
  23.  
  24. // body
  25. always @(posedge clk)
  26. if (we) // write operation
  27. ram[addr] <= din;
  28. // read operation
  29. assign dout = ram[addr];
  30.  
  31. endmodule


  • Opción 2

En nuestro circuito impreso agregamos una memoria tipo SRAM (Static Random Access Memory) con capacidad de 32K palabras de 8 bits cada una. Esta memoria tiene un rendimiento de alta velocidad y al tiempo consume poca potencia. Utiliza una señal de chip select (~CS) y una interfaz de periférico serial (SPI).

Set de instrucciones de la memoria

Lectura:

La memoria funciona con el flanco positivo del reloj serial. La memoria se habilita poniendo ~CS en estado bajo. Los primeros 8 bits que recibe el dispositivo en el pin SI (serial input) son para seleccionar la instrucción deseada que en este caso sería 0000 0011 como se indica en la tabla anterior; luego de recibir estos bits, la memoria recibe la dirección que se desea leer que consta de 16 bits. Luego de estos lo que se reciba por el pin SI sera un estado don't care. Después, la información almacenada en la dirección seleccionada pasa al pin SO (serial output). Después que la palabra inicial se ha puesto en SO, el dato almacenado en la siguiente posición de memoria se lee y así sucede secuencialmente, esto sucede porque el apuntador interno para la dirección de memoria se incrementa automáticamente luego que una palabra ha sido leida, esto puede suceder hasta que la se ha leido la palabra 32 y en ese momento el apuntador vuelve a ser cero y continua enviando los datos a SO.

Diagrama de tiempo de la lectura

Escritura:

Luego que se ha puesto ~CS se ha puesto en bajo, SI recibe en los 8 primeros bits la instrucción que en este caso es 0000 0010 y en los siguientes 16 bits recibe la dirección de memoria en la que se desea escribir. Luego de los 16 bits SI comienza a recibir los datos que de van a almacenar; en este momento SO se encuentra en alta impedancia. Cuando se termina de escribir una palabra, el apuntador interno de la dirección se incrementa automáticamente a la siguiente posición de memoria esto puede seguir por las 32 palabras de la memoria y cuando de terminan las 32 palabras, el apuntador vuelve a la posición 0 de memoria. El ciclo se termina cuando ~CS se pone en alto de nuevo.

Diagrama de tiempo de la Escritura

[edit] UNIÓN

Este módulo contiene al ADC, la memoria y la FFT.


RTL de la unión

[edit] FFT

Transformada rápida de Fourier: en esta etapa se realiza el análisis del frecuencia de la señal discreta que ya tenemos.

Diagrama flujo FFT
Diagrama flujo mariposa
Proceso de Conversión

Las señales que recibamos las vamos a clasificar en 3 canales de frecuencia principalmente:

         * Graves: son las señales que estan entre 20Hz y 256Hz.
         * Medios: son las señales que estan entre 256Hz y 2KHz.
         * Agudos: son las señales que estan entre 2KHz y 20KHz.

El algoritmo de la FFT a trabajar, descompone la DFT de N puntos en transformadas más pequeñas; una DFT de N puntos es descompuesta en dos DFT’s de N/2 puntos, cada DFT de N/2 puntos se descompone a su vez en dos DFT’s de N/4 puntos y así sucesivamente. Al final de la descomposición se obtienen N/2 DFT´s de 2 puntos cada una; la transformada más pequeña viene determinada por la base de la FFT, para una FFT de base 2, N debe ser una potencia de 2 y la transformada más pequeña es la DFT de 2 puntos.

Para implementar la FFT existen dos procedimientos: diezmado en el tiempo (DIT del inglés Decimation In Time) y diezmado en frecuencia (DIF del inglés Decimation In Frequency); el primero, trabaja con los coeficientes desordenados y al final como resultado de las operaciones en estructura mariposa resultan ordenados, en cambio, el segundo trabaja de forma inversa, inicia ordenado y termina desordenado.


Algoritmo FFF en Base 2 y Diezmado en el tiempo:

Consideremos el cálculo de la DFT de N = 2v a partir de dividir la secuencia de datos de N puntos, en dos secuencias de N/2, correspondientes a las muestras pares e impares de x[n], respectivamente, esto es:


EFFT1.png


Obsérvese, que se realizó el diezmado de la secuencia x[n], una vez. La DFT de N puntos puede expresarse ahora en términos de las DFTs de las secuencias diezmadas como sigue:


EFFT2.png


Pero EFFT3.png. Sustituyendo esta igualdad en la expresión anterior se obtiene:


EFFT4.png


donde F1(k) y F2(k) son las DFTs de N/2 puntos de las secuencias f1[n] y f2[n].

Puesto que F1(k) y F2(k) son periódicas, de periodo N/2, tenemos F1(k+N/2)= F1(k) y F2(k+N/2)= F2(k); por otro lado, se cumple que EFFT5.png, por lo que se puede rescribir la expresión anterior de la siguiente manera:


EFFT6.png


Se observa que el calculo directo de F1(k) requiere (N/2)2 multiplicaciones complejas al igual que F2(k). Además, se requieren N/2 multiplicaciones más para calcular EFFT7.png . De aquí que el calculo de X(k) requiere N2/2 + N/2 multiplicaciones complejas. El primer paso realizado de una reducción en el número de multiplicaciones de N2 a N2/2 + N/2, lo que equivale aproximadamente a dividir por dos el número de multiplicaciones cuando N es grande.

Habiendo realizado el diezmado en tiempo una vez, podemos repetir el proceso para cada una de las secuencias f1[n] y f2[n]. Por lo tanto, se obtendrá dos secuencias de N/4 puntos:


EFFT8.png


Calculando las DFTs de N/4 puntos se obtienen las DFTs de N/2 puntos F1(k) y F2(k) a partir de las siguientes relaciones:


EFFT9.png


donde Vij(k) son las DFTs de N/4 puntos de las secuencias vij[n].

Se observa que el calculo de Vij(k) requiere 4(N/4)2 multiplicaciones y por lo tanto el calculo de F1(k) y F2(k) puede realizarse con N2/4 + N/2 multiplicaciones complejas. Se requieren N/2 multiplicaciones complejas más para calcular X(k) a partir de F1(k) y F2(k). Consecuentemente, el número total de multiplicaciones necesarias N2/4 + N/2 se reduce otra vez aproximadamente por un factor de dos.

El diezmado de la secuencia de datos se repite v = log2 N veces, ya que se tienen N = 2v datos. Por lo tanto el número total de multiplicaciones complejas se reduce a (N/2) log2 N , mientras que el número de sumas complejas es N log2 N .


Comparación entre la cantidad de multiplicaciones complejas a realizar por parte de la DFT y el algoritmo FFT de base 2


Algoritmo completo para la FFT de diezmado en tiempo de 8 puntos


Como puede observarse, el calculo que se realiza en cada etapa, el cual consiste en aplicar las operaciones de una transformada DFT de dos puntos o “mariposa”; en general, cada mariposa implica una multiplicación y dos sumas complejas. Para N puntos, tenemos N/2 mariposas por cada etapa del proceso y log2N etapas de mariposas. Por lo tanto podemos guardar el resultado de cada operación de la mariposa (A, B), en las mismas posiciones de sus operandos (a, b). En consecuencia, necesitamos una cantidad fija de memoria, en concreto 2N registros de almacenamiento para guardar los resultados de N números complejos.


Mariposa básica del algoritmo para la FFT de diezmado en el tiempo


Simplificando aun más el proceso del algoritmo mediante la mariposa, se tiene lo siguiente:


EFFT13.png


dando como resultado un algoritmo aun más sencillo:


Algoritmo simplificado para la FFT de diezmado en tiempo de 8 puntos


Algoritmo simplificado para la FFT de diezmado en tiempo de 64 puntos


Ahora, para realizar la transformada de acuerdo a la estructura mariposa es necesario ser cuidadoso en el orden de las operaciones, así como también con el orden de los coeficientes, para ello se siguen las siguientes consideraciones:

Operaciones:


Esquema de operaciones


Coeficientes:

El orden de los coeficientes al inicio de la mariposa depende del número de de puntos y bits a manejar, por ejemplo, en este caso tenemos N=2n, en donde N=8, por lo tanto el número de bits a usar son n=3:


Esquema de coeficientes


En la gráfica se puede ver claramente que la clave al momento de ordenar los coeficientes iniciales se encuentra en invertir el orden de los bits correspondientes a dicho coeficiente.

  • Código de la Función Mariposa en Verilog:
  1.    function  [17:0] mariposa;
  2.                 input [17:0] wn;
  3. 		input [17:0] s1,s2;
  4. 		input n; //signo entre factores
  5. 		reg [8:0] m1,m2,m3,m4,m5,m6,m7,m8;
  6.       begin
  7. //------------------ PARA EL FACTOR  Wn*x --------------------------
  8.                         m1=wn[16:9]*s2[16:9]; //Real
  9. 			m2=wn[16:9]*s2[7:0]; //Complejo
  10. 			m3=wn[7:0]*s2[16:9]; //Complejo
  11. 			m4=wn[7:0]*s2[7:0]; //Real (j*j)
  12.  
  13. 			//Signos parte real
  14. 			if((wn[17]==1 && s2[17]==1)||(wn[17]==0 && s2[17]==0))	m1[8]=0;
  15. 			else if((wn[17]==0 && s2[17]==1)||(wn[17]==1 && s2[17]==0))	m1[8]=1;
  16.  
  17. 			//Signos parte compleja
  18. 			if((wn[17]==1 && s2[8]==1)||(wn[17]==0 && s2[8]==0))	m2[8]=0;
  19. 			else if((wn[17]==0 && s2[8]==1)||(wn[17]==1 && s2[8]==0))	m2[8]=1;			
  20.  
  21. 			//Signos parte compleja
  22. 			if((wn[8]==1 && s2[17]==1)||(wn[8]==0 && s2[17]==0))	m3[8]=0;
  23. 			else if((wn[8]==0 && s2[17]==1)||(wn[8]==1 && s2[17]==0))	m3[8]=1;
  24.  
  25. 			//Signos parte real (ahi q tener en cuenta el q j*j=-1)
  26. 			if((wn[8]==1 && s2[8]==1)||(wn[8]==0 && s2[8]==0))	m4[8]=1;
  27. 			else if((wn[8]==0 && s2[8]==1)||(wn[8]==1 && s2[8]==0))	m4[8]=0;
  28.  
  29. 			//Sumas parte compleja
  30. 			if(m2[8]==0 && m3[8]==0) 
  31. 				if (n==0) m6={1'b0,m2[7:0]+m3[7:0]};
  32. 				else m6={1'b1,m2[7:0]+m3[7:0]};
  33. 			else if(m2[8]==1 && m3[8]==1) 
  34. 				if (n==0) m6={1'b1,m2[7:0]+m3[7:0]};
  35. 				else m6={1'b0,m2[7:0]+m3[7:0]};
  36. 			else if((m2[8]==0 && m3[8]==1)&&(m2[7:0]>=m3[7:0])) 
  37. 				if (n==0)  m6={1'b0,m2[7:0]-m3[7:0]};
  38. 				else m6={1'b1,m2[7:0]-m3[7:0]};
  39. 			else if((m2[8]==0 && m3[8]==1)&&(m2[7:0]<m3[7:0])) 
  40. 				if (n==0)  m6={1'b1,m3[7:0]-m2[7:0]};
  41. 				else m6={1'b0,m3[7:0]-m2[7:0]};
  42. 			else if((m2[8]==1 && m3[8]==0)&&(m2[7:0]>m3[7:0])) 
  43. 				if (n==0)  m6={1'b1,m2[7:0]-m3[7:0]};
  44. 				else m6={1'b0,m2[7:0]-m3[7:0]};
  45. 			else if((m2[8]==1 && m3[8]==0)&&(m2[7:0]<=m3[7:0])) 
  46. 				if (n==0)  m6={1'b0,m3[7:0]-m2[7:0]};
  47. 				else m6={1'b1,m3[7:0]-m2[7:0]};
  48.  
  49. 			//Sumas parte real 
  50. 			if(m1[8]==0 && m4[8]==0) 
  51. 				if (n==0) m5={1'b0,m1[7:0]+m4[7:0]};
  52. 				else m5={1'b1,m1[7:0]+m4[7:0]};
  53. 			else if(m1[8]==1 && m4[8]==1) 
  54. 				if (n==0) m5={1'b1,m1[7:0]+m4[7:0]};
  55. 				else m5={1'b0,m1[7:0]+m4[7:0]};
  56. 			else if((m1[8]==0 && m4[8]==1)&&(m1[7:0]>=m4[7:0])) 
  57. 				if (n==0) m5={1'b0,m1[7:0]-m4[7:0]};
  58. 				else m5={1'b1,m1[7:0]-m4[7:0]};
  59. 			else if((m1[8]==0 && m4[8]==1)&&(m1[7:0]<m4[7:0])) 
  60. 				if (n==0) m5={1'b1,m4[7:0]-m1[7:0]};
  61. 				else m5={1'b0,m4[7:0]-m1[7:0]};
  62. 			else if((m1[8]==1 && m4[8]==0)&&(m1[7:0]>m4[7:0])) 
  63. 				if (n==0) m5={1'b1,m1[7:0]-m4[7:0]};
  64. 				else m5={1'b0,m1[7:0]-m4[7:0]};
  65. 			else if((m1[8]==1 && m4[8]==0)&&(m1[7:0]<=m4[7:0])) 
  66. 				if (n==0) m5={1'b0,m4[7:0]-m1[7:0]};
  67. 				else m5={1'b1,m4[7:0]-m1[7:0]};
  68.  
  69. //------------------ PARA EL FACTOR x ------------------------------
  70.  
  71. 			//Sumas parte compleja
  72. 			if(s1[8]==0 && m6[8]==0) m8={1'b0,s1[7:0]+m6[7:0]};
  73. 			else if(s1[8]==1 && m6[8]==1) m8={1'b1,s1[7:0]+m6[7:0]};
  74. 			else if((s1[8]==0 && m6[8]==1)&&(s1[7:0]>=m6[7:0])) m8={1'b0,s1[7:0]-m6[7:0]};
  75. 			else if((s1[8]==0 && m6[8]==1)&&(s1[7:0]<m6[7:0])) m8={1'b1,m6[7:0]-s1[7:0]};
  76. 			else if((s1[8]==1 && m6[8]==0)&&(s1[7:0]>m6[7:0])) m8={1'b1,s1[7:0]-m6[7:0]};
  77. 			else if((s1[8]==1 && m6[8]==0)&&(s1[7:0]<=m6[7:0])) m8={1'b0,m6[7:0]-s1[7:0]};
  78.  
  79. 			//Sumas parte real 
  80. 			if(s1[17]==0 && m5[8]==0) m7={1'b0,s1[16:9]+m5[7:0]};
  81. 			else if(s1[17]==1 && m5[8]==1) m7={1'b1,s1[16:9]+m5[7:0]};
  82. 			else if((s1[17]==0 && m5[8]==1)&&(s1[16:9]>=m5[7:0]))  m7={1'b0,s1[16:9]-m5[7:0]};
  83. 			else if((s1[17]==0 && m5[8]==1)&&(s1[16:9]<m5[7:0])) m7={1'b1,m5[7:0]-s1[16:9]};
  84. 			else if((s1[17]==1 && m5[8]==0)&&(s1[16:9]>m5[7:0])) m7={1'b1,s1[16:9]-m5[7:0]};
  85. 			else if((s1[17]==1 && m5[8]==0)&&(s1[16:9]<=m5[7:0])) m7={1'b0,m5[7:0]-s1[16:9]};
  86.  
  87. 			mariposa={m7,m8};
  88.       end
  89.    endfunction

La función anteriormente descrita es la base de nuestra FFT, ya que el desarrollo de la misma no es más que el llamado a está función de forma recursiva para cada etapa del algoritmo mariposa de la FFT.

  • Simulación:

Para la simulación se tomo como salida del ADC 8 muestras de 10 bits, que para efectos prácticos tomará valores entre 8 y 1.


Simulación de la FFT de 8 puntos


Para los arreglos de salida X0 a X7 la distribución de bits es:

X[17] X[16:9] X[8] X[7:0]
Signo # Real Signo # Complejo
RTL general de la FFT de 8 puntos
RTL interno de la FFT de 8 puntos


  • Para la simulación de la FFT de 64 puntos se tomaron todos los coeficientes de entrada como 2 y se uso un contador para la realización de cada etapa de la mariposa, por lo cual, se observa claramente que la salida final de la FFT se obtiene en la etapa 6:


Simulación de la FFT de 64 puntos


Magnitud

Debido a que el espectro de audio se representa como "Magnitud contra Frecuencia" se desarrollo el siguiente código basados en dos conceptos:

  1. La magnitud de un número complejo es: EC magnitud.png
  2. Aproximación de la raíz cuadrada mediante el Algoritmo Babilónico: este se centra en el hecho de que cada lado de un cuadrado es la raíz cuadrada del área.
    • Pasos para hallar la Raíz(x):
    1. Escoja dos números b y h tales que bh = x
    2. Si h≈b vaya al paso 6, si no, vaya al paso 3
    3. Asigne b=(b+h)/2
    4. Asigne h=x/b
    5. Vaya al paso 2
    6. Escriba (x)1/2≈b
Diagrama flujo suma de cuadrados
Diagrama flujo raíz cuadrada
  • Código:
  1. `timescale 1ns / 1ps
  2.  
  3. module Magnitud(clk,X2,X4,X6,M2,M4,M6);
  4.  
  5. input clk;
  6. input [21:0] X2,X4,X6;
  7. output wire [20:0] M2,M4,M6;
  8.  
  9.  
  10.    function [20:0] suma_cuadrados;
  11.       input [21:0] X;
  12. 		reg [9:0] m1,m2;
  13.       begin
  14.          m1=X[20:11];								//X
  15. 			m2=X[9:0];									//Y
  16. 			suma_cuadrados=(m1*m1)+(m2*m2);		//X^2+Y^2
  17.       end
  18.    endfunction
  19.  
  20. assign M2=suma_cuadrados(X2);
  21. assign M4=suma_cuadrados(X4);
  22. assign M6=suma_cuadrados(X6);
  23.  
  24. endmodule


  • Simulación:

Para la simulación se evaluaron valores extremos tales como: 1023+j1023 y 0+j0


Simulación de Magnitud


RTL general de Magnitud

[edit] RESOLUCIÓN

Para saber que frecuencias podemos llegar a visualizar se tienen las siguientes consideraciones matemáticas:

Resolución Frecuencial

En donde fs es la frecuencia de muestreo (50KHz) y N es el número de puntos de la FFT (8), así pues, podemos obtener de forma sencilla la resolución frecuencial, que en nuestro caso es de 6.25KHz.

Considerando la resolución frecuencial y el numero de puntos de la FFT podemos obtener la siguiente tabla:

Coeficiente k Frecuencia
0 0
1 6.25KHz
2 12.5KHz
3 18.75KHz
4 25KHz
5 31.25KHz
6 37.5KHz
7 43.75KHz


Los coeficientes elegidos para la visualización son 1,2 y 3.

[edit] VISUALIZACIÓN

El control de la matriz de leds se realizo como una maquina de estados, habilitando las columnas de acuerdo a la frecuencia deseada y así mismo, evaluando la magnitud correspondiente para definir el número de leds que se encenderan las filas; además de esto, fue necesario realizar un buffer de tal manera que los datos visualizador se encontraran constantes el tiempo suficiente en la variables de magnitud evaluadas, esto con el fin de obtener una vizualización adecuada, ya que los datos varian muy rápido y no es posible observarlos por mucho tiempo en la matriz, lo que causaba que los leds estuviesen todo el tiempo en el dato que se presentaba mayor número de veces.


Código:

  1. module Matriz(
  2. input clk,
  3. input start,
  4. input reset,
  5. input [20:0] M1,M2,M3,
  6. output reg [4:0] columna,
  7. output reg [6:0] fila
  8. );
  9.  
  10. reg clk_frec;
  11. reg [23:0]  counter;
  12. reg buff_start;
  13. reg [20:0] buff_M1;
  14. reg [20:0] buff_M2;
  15. reg [20:0] buff_M3;
  16. reg [31:0] cont1;
  17. reg [31:0] cont2;
  18. reg [31:0] cont3;
  19. reg [31:0] cont4;
  20.  
  21. initial 
  22. begin
  23. 	columna=1;
  24. 	fila=1;
  25. 	counter<=32'd0;
  26. 	buff_M1=0;
  27. 	buff_M2=0;
  28. 	buff_M3=0;
  29. 	clk_frec=0;
  30. 	cont1=0;
  31. 	cont2=0;
  32. 	cont3=0;
  33. 	cont4=0;
  34. end
  35.  
  36. always@(posedge clk)
  37. begin
  38. 	if(reset) 
  39. 	begin
  40. 		buff_start=1'd0;
  41. 		clk_frec=0;
  42. 		counter=0;
  43. 		cont1=0;
  44. 		cont2=0;
  45. 		cont3=0;
  46. 		cont4=0;
  47. 	end
  48. 	if(~start)
  49. 	begin
  50. 		buff_start=1'd1;
  51. 	end
  52. 	if(buff_start)
  53. 	begin
  54. 		if(counter<24'd500) 
  55. 		begin
  56. 			counter=counter+1'd1;	
  57. 			clk_frec=0;
  58. 		end
  59. 		else if (counter==24'd500)
  60. 		begin
  61. 			clk_frec=1;
  62. 			counter=24'd0;
  63. 		end
  64. 		if(clk_frec)
  65. 		begin	
  66.                 cont4=cont4+1'd1;
  67. 		if(cont4==32'd1000)
  68. 		begin
  69.                         cont4=0;
  70. 			buff_M1=M1;
  71. 			buff_M2=M2;
  72. 			buff_M3=M3;
  73. 		end
  74.         case(cont3)
  75.         32'd0:begin
  76. 			if(buff_M1==21'd0) begin cont1=0; cont2=0; cont3=1; end
  77. 			else if(21'd0<buff_M1 && buff_M1<=21'd348843) begin cont1=1; cont2=1; cont3=1; end
  78. 			else if(21'd348843<buff_M1 && buff_M1<=21'd697686) begin cont1=2; cont2=1; cont3=1; end
  79. 			else if(21'd697686<buff_M1 && buff_M1<=21'd1046529) begin cont1=3; cont2=1; cont3=1; end
  80. 			else if(21'd1046529<buff_M1 && buff_M1<=21'd1395372) begin cont1=4; cont2=1; cont3=1; end
  81. 			else if(21'd1395372<buff_M1 && buff_M1<=21'd1744215) begin cont1=5; cont2=1; cont3=1; end
  82. 			else if(21'd1744215<buff_M1 && buff_M1<=21'd2093058) begin cont1=6; cont2=1; cont3=1; end
  83. 		end
  84.         32'd1:begin
  85. 			if(buff_M2==21'd0) begin cont1=0; cont2=0; cont3=2; end
  86. 			else if(21'd0<buff_M2 && buff_M2<=21'd348843) begin cont1=1; cont2=2; cont3=2; end
  87. 			else if(21'd348843<buff_M2 && buff_M2<=21'd697686) begin cont1=2; cont2=2; cont3=2; end
  88. 			else if(21'd697686<buff_M2 && buff_M2<=21'd1046529) begin cont1=3; cont2=2; cont3=2; end
  89. 			else if(21'd1046529<buff_M2 && buff_M2<=21'd1395372) begin cont1=4; cont2=2; cont3=2; end
  90. 			else if(21'd1395372<buff_M2 && buff_M2<=21'd1744215) begin cont1=5; cont2=2; cont3=2; end
  91. 			else if(21'd1744215<buff_M2 && buff_M2<=21'd2093058) begin cont1=6; cont2=2; cont3=2; end
  92.         end
  93.         32'd2:begin
  94. 			if(buff_M3==21'd0) begin cont1=0; cont2=0; cont3=0; end
  95. 			else if(21'd0<buff_M3 && buff_M3<=21'd348843) begin cont1=1; cont2=3; cont3=0; end
  96. 			else if(21'd348843<buff_M3 && buff_M3<=21'd697686) begin cont1=2; cont2=3; cont3=0; end
  97. 			else if(21'd697686<buff_M3 && buff_M3<=21'd1046529) begin cont1=3; cont2=3; cont3=0; end
  98. 			else if(21'd1046529<buff_M3 && buff_M3<=21'd1395372) begin cont1=4; cont2=3; cont3=0; end
  99. 			else if(21'd1395372<buff_M3 && buff_M3<=21'd1744215) begin cont1=5; cont2=3; cont3=0; end
  100. 			else if(21'd1744215<buff_M3 && buff_M3<=21'd2093058) begin cont1=6; cont2=3; cont3=0; end
  101.         end
  102.         default: begin cont3=0; cont1=0; cont2=0; end
  103.         endcase
  104. 		end
  105.    	end
  106. end
  107.  
  108. always@(cont1)
  109. begin
  110. 	case(cont1)
  111. 		32'd0: fila=7'b1111111;
  112. 		32'd1: fila=7'b1111100;
  113. 		32'd2: fila=7'b1111000;
  114. 		32'd3: fila=7'b1110000;
  115. 		32'd4: fila=7'b1100000;
  116. 		32'd5: fila=7'b1000000;
  117. 		32'd6: fila=7'b0000000;
  118. 	endcase
  119. end
  120.  
  121. always@(cont2)
  122. begin
  123. 	case(cont2)
  124. 		32'd0: columna=5'b11111;
  125. 		32'd1: columna=5'b01111;
  126. 		32'd2: columna=5'b10111;
  127. 		32'd3: columna=5'b11011;
  128. 	endcase
  129. end
  130.  
  131. endmodule

[edit] Software

  • Inicializar el ADC: la principal tarea software que se va a realizar con este proyecto es mandarle la informacion del canal que se va a utilizar en el ADC.
void adc_init()
{
uniont0->channel=0x00;	
return;
}
  • Puerto serial

Para realizar algunas pruebas sobre el funcionamiento del proyecto, fue necesario trabajar con el puerto serial. En este se verificó que realmente los datos que entran a la memoria, son los mismos datos que llegan a la FFT. El siguiente es el código realizado para manejar la uart:

#include "soc-hw.h"
volatile uint32_t *p;
int main()
{
  irq_disable();
  adc_init();
 
unsigned char j=0;
for(;j<1;){
	*p=uniont0->miso;
	switch(*p){
	case(0x00):uart_putchar(*p+0x30);break;
	case(0x01):uart_putchar(*p+0x31);break;
	default:  uart_putchar(*p+0x3D);break;
	}	  
}
return(0);
}

[edit] Análisis Económico

ANÁLISIS DE COSTOS DEL PROYECTO COSTO DEL PROTOTIPO

Elementos de circuitos varios $42,000

Pcb $26,000

SIE $195,000

Total $263,000

En el Cuadro anterior se observan los costos de insumos utilizados en la realizacin del proyecto. En elementos de circuitos varios, incluimos el costo de resistencias, cables, conectores, transistores, entre otros. No se incluyeron costos de software debido a que se utilizó software libre para la realización de todo el proyecto. Decidimos cobrar $30.000 por cada hora de trabajo en este proyecto basándonos en la dificultad del proyecto, la cantidad de conocimientos específicos necesarios para abordar un problema como el planteado; trabajamos alrededor de 448 horas, durante todo el semestre, por lo tanto el trabajo tiene un costo de $13.440.000. en total. Si tuvieramos que cobrar por este prototipo, cobraríamos alrededor de $15.000.000 teniendo en cuenta algunos gastos demás con la energía del sitio de trabajo, el costo de internet, entre otros.

COSTOS DE PRODUCIR 100 UNIDADES

Matrices 239 dólares

ULN2803 35 dólares

Resistencias, condensadores y diodos 39 dólares

Pcb 300 dólares

Conectores 500 dólares

Otros costos 100 dólares

Total 1213 dólares

Hecho por Carolina y Alejandra

Personal tools
Namespaces
Variants
Actions
Navigation
interactive
Toolbox
Print/export