Microprocesador Microprocesador Notas de Beiyou State Academy of Things

Introducción-Chat casual

¿Qué es un sistema embebido? Sistemas informáticos dedicados. Se pueden hacer algunas compensaciones en la arquitectura de la computadora, periféricos, etc. para funciones especializadas.

Limitaciones habituales: Costo (como implementar una gran cantidad de nodos sensores), Límites de tamaño y peso (escenarios de aplicación específicos, como sistemas de detección de flujo de alcantarillado, que requieren nodos pequeños), Límites de potencia y energía (como implementación en entornos extremos, Nodo de recolección de la cima de la montaña del Himalaya, inconveniente para cargar), Medio ambiente (impermeable, resistencia a altas temperaturas, etc.)

La diferencia entre los dos sistemas integrados de MCU y MPU: enfoque en control o procesamiento. Los controles como la iluminación, los brazos robóticos y los motores son todos. Procesamiento, como los datos recopilados por la cámara para el procesamiento de imágenes.

Lenguaje de programación: cerca de la parte inferior de la computadora, principalmente usando ensamblador y c.

SO: No hay necesariamente una estructura de sistema operativo en un sistema integrado. Para decirlo sin rodeos, el sistema operativo es para ayudar a administrar mejor la programación de recursos informáticos. Ahora analicemos la función principal de nuestro código lab2:

void main(){
    
    
    //background
    while(1){
    
    
        
    }
}

void IRQ_Handler(){
    
    
    //interrupt handler function, frontground
}

Parte de fondo: un bucle que realiza repetidamente las tareas a realizar.

Este enfoque se ve bien a primera vista. Pero piense en lo que puede hacer una computadora de este tipo, solo puede realizar todas las tareas una y otra vez en orden, y no hay forma de cambiar el orden.

Parte en primer plano: procesamiento de interrupciones, la función uart_rx_isr en nuestro lab2 generalmente usa IRQ_Handler (de hecho, si rastrea la fuente de uart_rx_isr en lab2, encontrará que en realidad es llamado por IRQ_Handler, este método activa la interrupción cuando la interrupción correspondiente es comenzó se llamará automáticamente).

El sistema combinado del anverso y el reverso sigue siendo un sistema básico sin sistema operativo, pero después de agregar la interrupción, nos permite usar la tarea de interrupción para interrumpir el sondeo en segundo plano y cambiar el orden de ejecución. Por ejemplo, cuando se envía el número de interrupciones del puerto serie, la CPU deja de lado el trabajo en segundo plano, maneja las interrupciones de primer plano y regresa después del procesamiento.

Nuestros cursos se limitan a contenido desarrollado en bare metal.

Una breve introducción a los sistemas informáticos.

Arquitectura Von Neumann

Controlador de unidad aritmética (integrado en la CPU) memoria memoria principal dispositivo de entrada dispositivo de salida IO y tres buses de transmisión: datos, control, bus de datos de dirección/bus de control/bus de direcciones.

1686650488954

Como se mencionó anteriormente, MPU se enfoca en el cálculo y procesamiento de datos, mientras que MCU tiene el control, por lo que MPU no necesita algunos periféricos para controlar componentes externos.

Arquitectura de Harvard

La diferencia con von Neumann es que las instrucciones y los datos se almacenan por separado. De esta manera, la eficiencia de la búsqueda de índices, la obtención de índices y la obtención de números es alta.

Concepto de programa almacenado

Hay dos partes principales: la RAM almacena programas y datos, y la ROM almacena programas y datos de solo lectura sin cambios.

La instrucción de ejecución de la CPU es la ejecución repetida de tres pasos: buscar decodificar ejecutar buscar instrucción decodificar ejecución

asamblea

Si el lenguaje de alto nivel es equivalente a traducir palabras humanas a computadoras, el lenguaje ensamblador es equivalente a traducirnos lenguaje de computadora. Está más cerca de la capa inferior, por lo que la eficiencia operativa es mayor y el hardware se puede operar directamente.

ADD r3, r1, r2 	;r3 = r1 + r2
SUB r3, r0, r3 
MOV r2, r1 		;r2 = r1

; es un comentario. La variable r123 es un registro registro, que es una parte que puede manipular el hardware, y podemos manipular el hardware asignándole un valor.

El lenguaje de alto nivel se traduce a lenguaje ensamblador a través del compilador, y el lenguaje ensamblador se traduce a lenguaje de máquina binario a través del ensamblador.

arquitectura BRAZO

ARM es un conjunto de instrucciones y las instrucciones de ensamblaje mencionadas anteriormente se cuentan como instrucciones.

Lo interesante de ARM es que no fabrican dispositivos ARM, solo diseñan la arquitectura del conjunto de instrucciones y luego autorizan (núcleos de propiedad intelectual, núcleos IP) a otros fabricantes de semiconductores.

R: la aplicación, que se centra en el alto rendimiento, y muchas computadoras móviles se basan en la arquitectura ARM.

R: en tiempo real, centrándose en el tiempo real. Por ejemplo, Internet de los vehículos tiene altos requisitos para el rendimiento en tiempo real.

M: microcontrolador, utilizado en pequeños sistemas integrados, la placa que utilizamos.

La serie m tiene m0 a m7 (simplemente hablando, ¿el rendimiento aumenta gradualmente?) y es compatible con versiones anteriores, es decir, m7 es compatible con m0~m6.

SoC

Hay un pequeño chip negro en nuestro tablero con una cadena de caracteres stm32blabla escritos en él. Este es el núcleo de toda la placa, que es equivalente a la estructura de chip que incluye la arquitectura de computadora mencionada anteriormente, sistema en chips.

1686658267695

Reglas de diseño de Soc: primero seleccione el núcleo IP, diseñe el procesador ARM, además de una serie de estructuras de almacenamiento y periféricos IO, todo integrado en el chip negro.

El procesador del procesador ARM es una cobertura específica de la arquitectura, y hay muchos contenidos nuevos, como temporizadores.

Principalmente aprendemos la arquitectura m4.

1686658682835

Solo mire lo no opcional para obtener una descripción general, el código de acceso al núcleo del procesador y la interfaz de datos.

registro

Hemos introducido brevemente el registro anteriormente. De hecho, si desea procesar los datos en la memoria, primero debe ingresarlos en el registro del núcleo del procesador para realizar el cálculo y luego devolverlos.

El registro de armas es el siguiente:

1686659016141

Registros de propósito general: variables temporales que pueden almacenar datos de cálculo y similares.

SP: registro de puntero superior de la pila, que apunta a la parte superior de la pila.

LR: Para el retorno de la función, guarde la dirección de retorno. Por ejemplo, para llamar a una función, almacene el valor de PC en LR, y luego PC salta a la posición inicial de la función; cuando la función regresa, el valor de LR regresa a PC.

PC: Apunta al contador de programa donde el programa se está ejecutando actualmente (la dirección de la próxima instrucción a ejecutar). Después de obtener cada instrucción, la PC agrega automáticamente una instrucción, como el conjunto de instrucciones de 32 bits PC+=4B.

La serie PSR son registros de estado que indican el estado actual del programa. Por ejemplo, ¿es el modo de usuario actual o el modo kernel? ¿IPSR indica si las interrupciones están habilitadas actualmente? esperar.

Los xPSR incluyen:

  • APSR: Para el cálculo, como si lleva la bandera, si el resultado es 0, si es negativo, si se desborda, etc.
  • IPSR: relacionado con el manejo de interrupciones.
  • EPSR: relacionado con la ejecución, que indica el conjunto de instrucciones, si la interrupción continúa y otra información.

1686659814546

Mapa de memoria

El m4 tiene 4 g de espacio de memoria asignados a un espacio de forma predeterminada, y los usuarios también pueden modificarlo según sus preferencias. Hay región de código para almacenar código, región sram para almacenar datos, región periférica para almacenar periféricos, región ram externa, región de dispositivo externo, bus periférico privado interno (PPB).

1686669411390

Operaciones de banda de bits

operación de banda de bits.

Si queremos leer y escribir un determinado bit de datos de 32 bits, como el tercer bit (31:0 de izquierda a derecha, el tercer bit es el cuarto a la derecha), algunos registros nos permiten obtener directamente r[ 3], pero la mayoría de ellos no se pueden obtener directamente.

¿Como lidiar con? Si se escribe 1, entonces r|0000 0000 0000 0000 0000 0000 0000 1000.

Si escribe 0, entonces r & 1111 1111 1111 1111 1111 1111 1111 0111.

Leer: Ver si el resultado de r & 0000 0000 0000 0000 0000 0000 0000 1000 es 0.

Esto es muy problemático Por ejemplo, necesitamos escribir 1 en el tercer bit de los datos en 0x2000 0000. Código ensamblador detallado:

imagen-20230613232342659

LDR es cargar los siguientes datos en el registro frontal, [R1] es usar el valor de R1 como una dirección para obtener los datos almacenados en él.

Esto es engorroso, pero debido a la asignación de memoria podemos escribir y obtener los datos directamente en la "dirección de alias de bits".

imagen-20230613232721037

imagen-20230613232713587

Los bits 0 a 31 en 0x2000 0000 son:

0x2200 0000

0x2200 0004

0x2200 0008

0x2200 000c……

0x2200 007c

Así que obténgalo directamente y modifique los datos de 0x2200 000c.

0x2000 0000 se asigna a 0x2200 0000 es la asignación de área sram, 0x4000 0000 se asigna a 0x4200 0000 es la asignación de área periférica.

La operación es más rápida, la instrucción es menor y es más seguro acceder solo a un bit. Por ejemplo, se acaba de sacar el dato de 32 bits de 0x2000 0000. En este momento, se interrumpe y modifica el dato de 0x2000 0000. .En este momento, los datos que obtuvimos son los antiguos datos incorrectos Modificar Escríbalo después de terminar el tercer bit, lo que equivale a interrumpir el cambio por nada.

Imagen del programa

1686670722574

vector: Tabla de vectores, que almacena información como la dirección de la pila principal (MSP), la dirección de la excepción, etc.

start-up: El código de inicio cuando la placa se enciende o se enciende por primera vez.

código de programa: el código de programa que grabamos.

c lib code: código de función de biblioteca.

Cuando se reinicie, primero lea la dirección msp para encontrar dónde está el principal. Luego lea el vector de reinicio para ejecutar el código de inicialización del BIOS, y luego comience a leer la primera y la segunda instrucción...

1686670972039

endianidad

Dos especificaciones de almacenamiento.

Como números decimales, 1234, mil doscientos treinta y cuatro. Luego lo registramos en la base de datos, la dirección se almacena como 4321 de menor a mayor, y el bit 1 con mayor peso se almacena en la dirección más alta, que es el almacenamiento Big Endian. De lo contrario, el bit con un peso grande se almacena en la dirección baja y la dirección 1234 es de menor a mayor, lo que significa almacenamiento little endian. Ambos métodos son compatibles con m4.

Los términos "little endian" y "big endian" provienen del libro "Gulliver's Trabels" de Jonathan Swift, en el que las dos facciones en guerra no pueden decidir de qué extremo (little endian) debe provenir. huevo a convenir.

Aquí está la descripción de Jonathan Swift de la historia de la disputa endiana grande y pequeña en 1726:

"...Quiero decirles que las dos grandes potencias de Lilliput y Blefuscu han estado luchando encarnizadamente durante los últimos 36 meses. La guerra comenzó por la siguiente razón: Todos creemos que antes de comer huevos, el método primitivo es romper huevos El extremo grande, pero el abuelo del emperador actual comía huevos cuando era un niño, y se rompió un dedo una vez que rompió los huevos de acuerdo con el método antiguo, por lo que su padre, el emperador en ese momento, emitió un edicto ordenando a todos los súbditos romper los huevos al comer huevos. En el extremo más pequeño del huevo, los que violaron la orden fueron severamente castigados. La gente común estaba extremadamente disgustada con esta orden. La historia nos dice que ha habido seis rebeliones de esta manera. , en el que un emperador murió y otro perdió su trono. La mayoría de estas rebeliones fue instigada por los reyes y ministros de Blefuscu. Después de que la rebelión amainó, los exiliados siempre huyeron a ese imperio para encontrar rescate y refugio. Se estima que 11,000 personas en varias ocasiones preferirían morir antes que romper el huevo más pequeño. Sobre esta disputa, se han publicado cientos de obras importantes, pero los libros de la facción Daduan siempre han estado prohibidos, y la ley también estipula que nadie de esta facción puede ser un funcionario ". (Esta traducción está tomada de Jiang Jianfeng en Internet. Traducido "Los viajes de Gulliver" Volumen I Capítulo 4).

En su momento, Swift satirizaba el conflicto en curso entre Inglaterra (Lilliput) y Francia (Blefuscu). Danny Cohen, uno de los primeros pioneros de los protocolos de red, utilizó por primera vez estos dos términos para referirse al orden de los bytes y, desde entonces, el término se ha adoptado ampliamente.

Conocimientos básicos de big endian y little endian - Zhihu (zhihu.com)

Conjunto de instrucciones

Conjunto de instrucciones. El primer conjunto de instrucciones de arm era de 32 bits, con buen rendimiento y funciones potentes. Pero la eficiencia de procesamiento demasiado larga es baja.

El conjunto de instrucciones thumb-1 es de 16 bits, la eficiencia de procesamiento es alta, pero el rendimiento también se reduce. Si la arquitectura de brazo inicial admite dos conjuntos de instrucciones, es necesario cambiar de modo con frecuencia, lo que es ineficiente.

Más tarde, el conjunto de instrucciones thumb-2 incluía los primeros 16 bits y los nuevos 32 bits, y el rendimiento del conjunto de instrucciones mixto con el conjunto de instrucciones arm no disminuyó mucho, y el tamaño del código y la eficiencia de procesamiento seguían siendo altos.

Asamblea

Sintaxis de ensamblaje.

estructura secuencial

label							; 可省略,用于跳转到此位置
	助记符 operand1, operand2, … ; Comments
	
MOV r1, #0x01					; 数据0x01放入r1
MOV r1, #'A'					; 数据A的ascii码放入r1
MOV R0, R1 						; move R1 into R0
MOVS R0, R1 					; move R1 into R0, 并且更新APSR的状态

LDR R1, [R0]					; R0存的是一个地址值如0x2000 0000, 这个指令是取出R0代表的地址中的数据存入R1
STR R1, [R0]					; 写回去
LDR R0, =0x12345678 			; Set R0 to 0x12345678
; 等效于:
; LDR R0, [PC, #offset] 
; ...
; DCD 0x12345678
; 也就是先在文档末尾的一条指令里写入数据0x12345678,然后编译器自动计算PC+多少offset到达DCD的位置,把其值返给R0
; DCD是声明一个字 32bit,DCB是声明一个Byte
; 如果多个数值的声明可以用标签声明
LDR R3, =MY_NUMBER

ALIGN 4 ; 字要先用这个声明,代表停止长度
MY_NUMBER DCD 0x2000ABCC
HELLO_TEXT DCB “Hello\n”, 0 ; Null terminated string


LDRB R1, [R0]					; B: 只写8位,就是说R0地址处的数据写入R1后,R1高24位清零
SDRH R1, [R0]					; H: 只写16位

LDRSH R1, [R0]					; 视作signed有符号数,写16位

LDRB R0, [R1, #0x3]				; 从R1+3读取一个字节给R0
LDR R3, [R0, R2, LSL #2]		; 从R0+(R2<<2)读取一个字节给R3
LDR R0, [R1], #4				; 赋完值后,令R1=R1+4

ADD R0, R0, R1
ADDS R0, R0, R1					; 加完更新APSR状态,比如有溢出或者进位则更新
ADC R0, R1, R2					; R1+R2还要+APSR的carry位

; SUB SBC类似

MUL R0, R1, R2
UDIV R0, R1, R2
SDIV R0, R1, R2					; signed

Ejemplo: Debe estar firmado porque puede reducirse a negativo

1686672985123

Las instrucciones son de 1 palabra y media palabra. hw1 se usa para especificar la función, y hw2 es algunas extensiones, como datos inmediatos.

1686713591015

Las direcciones de menor a mayor son: 4F F0 0A 00 0A 68 10 44...

Cada vez que la PC obtiene media palabra hw, salta a la siguiente hw con +2B.

seleccionar estructura

	CMP R0, R1						; 相当于if,比较后更新APSR。EQ= LT< GT> LE<= GE >=
	BEQ BRANCH_1					; B是跳转,BL是跳转到函数执行完后返回,BX是根据地址最低位判断目标地址是arm还是thumb在决定跳转到整字还是半字。bx操作数不能是立即数,必须是寄存器
	B BRANCH_2
	
BRANCH_1
	...
	B IFEND							; 不写这个就继续执行BRANCH_2了,像switch的break
BRANCH_2
	...
B IFEND

estructura de bucle

WHILE_BEGIN 
	UDIV R2, R0, R1 ; R2 = n / x
	MUL R3, R2, R1 ; R3 = R2 * x
	CMP R0, R3 ; n == (n / x) * x
	BEQ WHILE_END
	SUBS R1, R1, #1 ; x--
	B WHILE_BEGIN ; loop back
WHILE_END

Pila

Hay una estructura de datos en el espacio de memoria similar a una pila. El puntero SP apunta a la parte superior de la pila.

La dirección de esta pila es de mayor a menor, es decir, para almacenar datos SP–, y para sacar datos SP++, que es similar a una pila de libros al revés.

Pila completa: el puntero sp apunta a los últimos datos en la parte superior de la pila.

Pila vacía: apunta a la siguiente ubicación vacía de los últimos datos para colocar los datos.

En nuestro curso, usamos una pila vacía, que apunta a la siguiente ubicación vacía. Para almacenar datos, primero se almacena en SP-4, y para obtener datos, primero es SP+4 y luego se extrae de la pila. Sin embargo, estas dos instrucciones no requieren que las ejecutemos manualmente, hay instrucciones especiales:

PUSH {R0, R4-R7} 	; Push r0, r4, r5, r6, r7
POP {R2-R3, R5} 	; Pop to r2, r3, r5。入栈出栈顺序不是按照书写顺序而是自动根据寄存器地址,高地址值给高地址寄存器

Almacenar 5 datos y retirar 3 datos.

Funciones

BL primero guarda el valor actual de la PC en LR, luego la PC salta a la dirección de la función,

BX LR salta a la dirección en LR para el retorno de la función.

Estándar de llamada de procedimiento de arquitectura (AAPCS): la especificación define qué registros son comunes a las funciones y funciones principales y cuáles son únicos.

arm AAPCS estipula: r0-r3 son registros de propósito general (similares a las variables globales), pero R4-R8, R10-R11 de funciones principales y no son comunes (similares a las variables temporales, estos valores cambiarán en la función, no es la función original), Para ser empujado a la pila para guardar. Los valores del registro general se guardan y restauran cuando se llama y se devuelve la función. Estos son realizados por la subfunción llamado-procedimiento que llama a la función original.

Llamada de función con parámetros simples: pase parámetros a R0-R3 como parámetros de función, empuje R4-R11 a la pila y luego salte a la función.

1686733381292

Uso de la memoria del programa

La ROM son datos de solo lectura, como constantes constantes.

1686733480351

constante, estático, volátil

Parece que no habrá demasiadas partes involucradas en la implementación del código específico, por lo que primero lo presentaré brevemente.

const es definir una variable constante, que no se puede modificar de nuevo después de la definición.

static generalmente define una función estática, y el valor en la función estática es universal, es decir, el valor de cada llamada a la función continúa desde el valor de la última llamada a la función.

volatile: una cosa muy importante en incrustado, ha aparecido varias veces en preguntas de exámenes suaves. Presumiblemente es para prohibir que el compilador optimice la variable para evitar errores innecesarios.

Por ejemplo, el compilador optimiza la variable num, de modo que cada vez que se modifique el valor de la variable num, no se escribirá en la memoria inmediatamente. Primero puede escribir el valor modificado en el registro y volver a escribirlo en la memoria. memoria cuando la función regresa.

Ahora, por ejemplo, si somos num+=5 en main, el num después del valor modificado se almacena temporalmente en el registro. Luego llamamos a la interrupción, leemos el valor numérico actual de la memoria y sumamos 1. Pero el valor en la memoria no ha cambiado, sigue siendo el valor original. Después de regresar, main escribe el valor numérico con sus propias manos en la memoria y, finalmente, el valor numérico en la memoria es solo +5, no +6 como esperábamos.

Las variables declaradas con volatile no se optimizarán de esta manera. Si el valor cambia, se volverá a escribir en la memoria inmediatamente. Aunque puede ser ineficiente, es seguro.

Interrupciones

Por ejemplo, la lógica de nuestro programa es encender una pequeña luz cuando se presiona un botón. El primer método es sondear, sigue observando: ¿se presiona el botón? No. ¿presionado? sin. ¿presionado? ...

Esto se debe principalmente a la baja eficiencia y al desperdicio de recursos de la CPU. Si el intervalo de sondeo es grande para ahorrar recursos, no puede responder a tiempo.

La interrupción permite que la CPU se concentre en procesar el segundo plano.Cuando se activa la interrupción, el segundo plano se elimina primero para procesar el primer plano. La conmutación simple de subprocesos múltiples también se puede realizar para metal sin sistema operativo.

proceso de manejo de excepciones

  1. Finaliza el comando que se está ejecutando actualmente.

  2. El valor de registro de modo actual se coloca en la pila para guardar.

    imagen-20230614171134845

  3. Cambia de modo.

  4. El PC LR se actualiza (según el valor proporcionado por el controlador de excepciones). La PC verifica la tabla de vectores de interrupción para ver dónde saltar y asigna el código EXC_RETURN a LR.

  5. Actualizar el estado de IPSR.

  6. Comience a ejecutar el código de excepción.

  7. Salir, BX LR devuelve el valor del código EXC_RETURN a la PC.

  8. Estallido.

Momento

Interrumpir la ejecución también requiere mucho tiempo.Se necesita una cierta cantidad de tiempo para guardar el estado del programa fuente, ejecutar la interrupción y recuperar.

FMax_Int: La frecuencia máxima de ejecución de interrupciones, es decir, el número máximo de interrupciones ejecutadas por unidad de tiempo.

F_CPU: Frecuencia de la CPU, es decir: cuantos ciclos de instrucción tiene la CPU por unidad de tiempo.

C_ISR: Cuántos ciclos para ejecutar contenido de interrupción.

C_Overhd: cuántos ciclos se utilizan para interrumpir el trabajo de preparación, como guardar y restaurar datos.

El ciclo necesario para interrumpir una ejecución: C_Overhd+C_ISR

因此,Eje FM _ I nt = FCPU / ( CISR + CO verhd ) F_{Max\_Int=}F_{CPU}/(C_{ISR}+C_{Overhd})FM a x _ I n t =FPCU _/ ( CYo SR+COverh d _ _ _)

U_int: La tasa de utilización realmente consumida por el procesamiento de interrupciones, la anterior es el valor máximo después de todo.

U int = FI nt / FM ax _ I nt U_{int}=F_{Int}/F_{Max\_Int}tuen t=Fyo n t/ FM a x _ I n t

Velocidad de ejecución de interrupción (igual que la frecuencia): F_Int

Velocidad de ejecución sin interrupción: (1-U_Int)*F_Int

GPIO

Salida de entrada de uso general,

E/S mapeada en memoria

Asigne dispositivos, controles y otros registros a la memoria. La ventaja es que la forma de acceder al dispositivo es la misma que la de la memoria, y no hay necesidad de diseñar circuitos IO complejos, lo cual es conveniente, la desventaja es que ocupa espacio en la memoria.

E/S asignada a periféricos

IO tiene un área de almacenamiento dedicada, que es diferente de la memoria, y también hay instrucciones de circuitos especiales para acceder a IO. La ventaja es ahorrar espacio en la memoria y puede saber claramente cuándo ocurre IO; la desventaja es que aumenta el costo de desarrollo y diseño.

GPIO

El IO de propósito general puede juzgar los niveles alto y bajo de los pines y puede asignar niveles altos y bajos a los pines para control.

El stm32 tiene varios grupos de GPIO, cada uno con 16 pines, que se pueden configurar como modos como pull-up de entrada y salida, así como funciones como temporizadores, puertos serie e interrupciones.

¿Qué es el modo pull-up? Si no está configurado para tirar hacia arriba y hacia abajo, cuando el pin está flotando (cuando la entrada no está configurada en un nivel alto o bajo), el pin flotante puede recibir interferencias de ondas electromagnéticas y otros problemas, lo que resulta en un estado de entrada incierto, hay 0 y 1, fácil de cometer errores.

Desplegable: el control del transistor se establece de manera predeterminada en tierra y se establece de manera predeterminada en un nivel bajo cuando no hay entrada.

Pull-up: el control del transistor está conectado al voltaje de funcionamiento del chip Vdd de forma predeterminada.

1686742220470

La mayoría de los pines tienen estas dos funciones, cuando inicializamos el GPIO, elegimos uno, y el registro controla el circuito correspondiente según el valor.

imagen-20230614193552367

Las señales de entrada y salida realmente se pueden llamar "señales". La entrada se define como 0-0,5 como nivel bajo, 0,5-Vdd como nivel alto y los valores fuera del rango no son válidos. La corriente de salida es solo de aproximadamente 5 mA, que es incapaz de controlar directamente algunos dispositivos.Podemos usar algunos circuitos como triodos, amplificadores, etc., y el circuito recibe una señal para saber que "la corriente de control debe salir" y luego emite una gran corriente.

Control

Cada puerto GPIO tiene:

Registros de configuración de 4 * 32 bits: información relacionada con la configuración, como entrada/salida, pull-up y pull-down, salida de drenaje abierto o salida push-pull, frecuencia de salida, etc.

  • Push-pull de salida push-pull: puede generar niveles altos y bajos.
  • Salida de drenaje abierto drenaje abierto: no hay capacidad para generar un nivel alto, si desea generar un nivel alto, debe configurar un circuito pull-up para la salida.

2 registros de datos de 32 bits: registros de datos de entrada y salida.

1 * Registros de configuración/reinicio de 32 bits: registros de configuración o reinicio.

1 * Registros de bloqueo de 32 bits: Registros de bloqueo.

Registro de selección de función alternativa de 2 * 32 bits.

Modo

Como se muestra en la figura, hay 32 pines, cada uno con dos bits para configurar 4 modos (entrada y salida analógica opcional).

1686743308300

Jalar

Solo hay 3 modos (sin tirar, tirar hacia arriba, tirar hacia abajo).

1686743360055

datos

Los registros de datos de entrada y salida están separados.

1686743538223

CMSIS

Permítanme hablar sobre la definición de la prueba primero:

CMSIS transforma registros mapeados en memoria en estructuras C

#define PORT0 ((struct PORT*)0x2000030)

1686747214412

Permítanme hablar sobre la comprensión discutida con algunas personas mayores integradas. El siguiente contenido no se puede escribir en el examen:

Profesor Li Ken: una serie de API y componentes de software lanzados por arm-M, que incluyen funciones básicas, bibliotecas DSP, compatibilidad con RTOS e interfaces de depuración.

Profesor Li Ken: Si la fábrica de chips no quiere agregar otra capa, CMSIS es suficiente, pero algunos fabricantes sellan otra capa, que puede llamarse la capa del controlador.

Profesor Li Ken: Además, CMSIS tiene una limitación, que es el procesador ARM Cortex-M de ARM, aunque es muy común, no todos los procesadores tienen este núcleo, esto necesita atención.

Sakaki: este tipo de archivos relacionados con el kernel, como los archivos de inicio y los archivos del kernel, están estipulados por CMSIS.

a6953d9ebb72f2ecd6cc4dbf569d406

Sakaki: Comparando los archivos de inicio de STM32F103 y GD32E23, encontraremos que son iguales:

711dd8daa73cb3dd198e50f32f6f86a

Sakaki: Lo que deben hacer los fabricantes de chips es volver a desarrollar las funciones de la biblioteca de acuerdo con la interfaz especificada por este brazo.

Cuenta de la estación C del Sr. Li Ken: Blog del arquitecto Li Ken_CSDN Blog-Programming Life, Blogger en el campo del bienestar de los fanáticos

Cuenta de la estación C del Sr. Sakaki: blog de Feng Zhenghao_CSDN blog-C language, MSP430F5529, blogger de dominio Linux

Por lo general, el grupo de intercambio del Sr. Li Ken discutirá muchos temas relacionados incrustados, y los estudiantes interesados ​​​​son bienvenidos a aprender [Doge]

Si está interesado en el contenido anterior, eche un vistazo.

ejemplo:

typedef enum {
    
    
Reset, //!< Resets the pin-mode to the default value.
Input, //!< Sets the pin as an input with no pull-up or pull-down.
Output, //!< Sets the pin as a low impedance output.
PullUp, //!< Enables the internal pull-up resistor and sets as input.
PullDown //!< Enables the internal pull-down resistor and sets as input.
} PinMode;

gpio_set_mode(P1_10, Input);
gpio_set_mode(P2_8, Output);
int PBstatus=gpio_get(P1_10); 
gpio_set(P2_8, 1);

El código anterior es el controlador proporcionado por el maestro. La idea general es seleccionar el pin y pasar parámetros específicos para configurar el modo y la salida.

Si te interesa, puedes echarle un vistazo a mi artículo.También es posible usar el cmsis definido por arm para desarrollar directamente:

Notas de estudio STM32_4 GPIO: LED, zumbador, botón, uso del sensor_Gray sea blog suelto-CSDN blog

#include "stm32f10x.h"
int main(void){
    
    
    /* 控制gpio需要三个步骤:开启rcc时钟,初始化,输入输出函数控制 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    GPIO_SetBits(GPIOA,GPIO_Pin_0);
    while(1){
    
    }
}

El desarrollo secundario de los controladores puede ayudar a simplificar.

Por supuesto, este párrafo está fuera de tema. El examen se entiende como "cmsis es una definición de macro variable asignada directamente a un registro; los controladores deben agregarle más comportamiento".

Comunicación serial

Comunicación en serie, un método de comunicación para enviar mensajes.

La cadena se refiere a la forma de enviar datos: transmisión en serie uno por uno, paralelo puede tener múltiples canales, cada canal envía datos al mismo tiempo y múltiples canales llegan al mismo tiempo.

La comunicación del puerto serial tiene simplex Simplex, half duplex Half Duplex, full duplex Full Duplex.

Dos métodos de transmisión: Sincrónica, que comparte un reloj; Asincrónica, que tiene su propio reloj.

La sincronización es muy simple, por ejemplo, el emisor y el receptor estipulan el flanco descendente de la señal del reloj para enviar y recibir.

1686749582568

Asíncrono: Debe coordinarse a través del protocolo de comunicación asíncrona Asynchronous Comm.Protocol.

1686749956698

1 indicador de bit de inicio para iniciar la transmisión, 7/8/9 bits de datos, 1 bit de paridad opcional, 1 bit de parada.

Ambas partes de RT deben tener la misma velocidad en baudios.

Por supuesto, esta es solo la comunicación en serie más simple porque solo hay dos partes. Si se comunican más partes, necesitamos verificar la dirección para determinar cuál se envía a cuál; ​​los datos requieren un método de verificación más complejo.

La comunicación asíncrona no requiere circuitos como relojes síncronos, y la sobrecarga es pequeña, pero es más difícil de desarrollar debido a la necesidad de bits de inicio y fin.

RS232

Comunicación asíncrona, voltaje estándar de polaridad invertida (-3 -15 es 1,3 15 es 0. Hay algunos otros estándares, como TTL es +5 es 1, -5 es 0).

Hay dos tipos de envío de datos, código ascii y binario, los cuales deben convertirse en transmisión binaria.

uarte

Para stm32f401.

Puerto serie asíncrono full-duplex.

Para procesar los datos del búfer RT (porque lleva tiempo enviar y recibir datos), podemos pasar la matriz del búfer, el puntero principal indica la posición que se ha enviado y el puntero final indica el final de los datos que se enviarán . Agregue nuevos datos, puntero de cola ++; envíe un dato, puntero de cabeza ++ hasta que toque el final.

Resulta que el remitente siempre ha enviado un nivel alto y el marco de inicio es un marco de nivel bajo para indicar que ha comenzado a enviar datos.

¿Cómo juzgar si 1 fotograma es de bajo nivel? Al muestrear múltiples veces en este marco, se juzga si es realmente un marco de bajo nivel.

¿Por qué muestreo múltiple? Debido a que las dos señales asíncronas tienen un cierto desplazamiento, el muestreo múltiple es preciso y se puede determinar si es realmente bajo para todo el cuadro.

El muestreo tiene una cierta frecuencia de muestreo, por no decir que realmente se puede muestrear como una señal analógica.

Sobremuestreo de tasa de muestreo = 16: esta es la frecuencia de muestreo máxima alcanzable en lugar de muestrear 16 veces por cuadro.

1686756691253

El receptor primero detecta el bit 0 por primera vez y comienza a sospechar: puede haber un mensaje en el puerto serie. Esta es la primera muestra del cuadro de inicio.

Luego verifique cada otro marco, 3 5 7 verifica 3 veces, si ambos son 0, significa que sí es posible.

Luego verifique continuamente 8910, si todavía hay dos 0, significa que de hecho es un cuadro de inicio.

1686756881390

8 tasa de muestreo Debido a que el intervalo de muestreo es largo, es más fácil encontrar niveles altos en los límites izquierdo y derecho, por lo que la tasa de tolerancia al error es baja. Pero más rápido.

calcular

Cálculo de la tasa de baudios:

T x / R x ( baudios ) = f PCLK 8 ∗ ( 2 − SOBRE 8 ) ∗ USARTDIV T_x/R_x(baudios)=\frac{f_{PCLK}}{8*(2-OVER8)*USARTDIV}Tx/ Rx( baud ) _ _=8 ( 2 SOBRE 8 ) U S A ART D I V _ _FPC L K

OVER8 es la tasa de sobremuestreo y fPCLK es la frecuencia de reloj.

USARTDIV es un número de punto flotante

¿Cómo se almacenan los números de punto flotante USARTDIV? Convertir a hexadecimal por algoritmo.

1686759124660

La parte fraccionaria se representa con un dígito hexadecimal. Por ejemplo, el Ejemplo 1 es C, que es 12. Después de la conversión, es 12/16, que es 0,75.

El ejemplo 2 se convierte a un sistema hexadecimal, es decir, 0,62*16 es aproximadamente igual a 10, que es A.

La parte entera se puede convertir directamente a hexadecimal, 25 en el ejemplo 2 se convierte en 19 y 27 en el ejemplo 1 se convierte en 1B.

Luego se concatena la parte fraccionaria del entero (hasta 3 bits enteros, 1 decimal, registro de 32 bits).

Temporizador

Quiero que el programa se ejecute regularmente, por ejemplo, el led 1s parpadea una vez. ¿Cómo hacerlo?

El primer método es un retardo estúpido, lo calculo yo mismo: bueno, el retardo (2000) es de aproximadamente 1 segundo. Luego en el programa retrasar, encender, retrasar, apagar...

Que desperdicio de recursos.

El segundo método, 32, tiene una interrupción de temporizador.

El principio general de la interrupción del temporizador es que el oscilador de cristal del reloj en las 32 salidas 0101010 a un ciclo de frecuencia fija... Hay un cnt en el temporizador, y se recibe ++ cuando se recibe un oscilador de cristal del reloj.

Podemos configurar el valor de desbordamiento del temporizador, por ejemplo, si el valor de desbordamiento es 1000, agregar cnt a 1000 activará automáticamente la interrupción del temporizador. Luego regrese a 0 y continúe con ++.

imagen-20230615014136641

Número de ciclos de ejecución: 1+1+1+1+(0xFFFFFFFF-1-1-1 hasta convertirse en 0x00FFFFFF)+(r0+1 tiempos de ejecución, 1 vez)

El temporizador también tiene algunos métodos de extensión, por ejemplo, podemos configurar ++ o –; podemos configurar la fuente de la señal como un reloj o una señal de onda cuadrada de entrada externa; podemos leer el valor de conteo...

El método común de nuestro material didáctico parece ser: activar una interrupción en 0 y luego restaurar el valor inicial.

1686764952191

PWM

¿Qué es PWM?

La modulación de ancho de pulso PWM (modulación de ancho de pulso), en un sistema con inercia, puede obtener los parámetros analógicos requeridos de manera equivalente al modular el ancho de una serie de pulsos, y se usa a menudo en campos como el control de velocidad del motor.

Por ejemplo, la velocidad de su bicicleta solo puede ser 100 y 0, y la señal eléctrica analógica solo puede emitir alta y baja.

Sin embargo, cuando andas en bicicleta, tienes inercia, pedalea a 100 de velocidad, pedalea a 0 de velocidad y pedalea a 100 de velocidad...

En general, la velocidad promedio de su bicicleta es 50 (suponemos que la aceleración no lleva tiempo, jaja)

Hay muchos escenarios de aplicación para esto, como configurar la frecuencia de parpadeo del LED: alta, baja, alta, baja, alta, baja..., debido a que la frecuencia es extremadamente alta, no podemos ver el parpadeo a simple vista, y el El efecto visual que se nos presenta es el de ser brillante con la mitad del brillo. Alto bajo bajo alto bajo bajo es 1/3 de brillo.

Por ejemplo, la velocidad del motor se ajusta de esta manera.

Entonces, ¿qué escenarios de aplicación tiene? Primero, captura de entrada Captura de entrada.

Para un sistema de inercia de este tipo, también podemos leer su forma de onda al revés para juzgar su velocidad. Por ejemplo, coloque un sensor de detección de velocidad en el motor y use la forma de onda de entrada como la señal de fuente de reloj del temporizador. El temporizador siempre es ++: registre el valor cnt al detectar los bordes ascendente y descendente, y calcule el intervalo de tiempo comparando la diferencia.

imagen-20230615020829378

En segundo lugar, comparación de salida comparación de salida.

El temporizador siempre es ++, en comparación con el umbral preestablecido, si son iguales, se activa la salida de interrupción.

1686767856060

Esto es PWM. El ciclo de trabajo es bastante bueno.

Temporizador de bajo consumo

Actualmente asumimos que la CPU siempre está funcionando, simplemente cambiando entre el fondo y el primer plano. Hay un temporizador de bajo consumo que hace que la CPU se coloque en un estado de bajo consumo cuando no se produce una interrupción del temporizador, y solo se inicia cuando se produce una interrupción del temporizador. (use __WFI() espere la instrucción)

imagen-20230621235021294

SysTick

Un reloj de sistema integrado de la serie M utiliza el reloj del procesador o el reloj de referencia como fuente de reloj.

Hay cuatro registros de bits:

imagen-20230621235527699

Cada asignación es una carga, hasta que llega a 0 y vuelve a cargar la asignación. ctrl es el control para habilitar el reloj del sistema. Esta es la parte de procesamiento de reloj de la estructura de datos y las funciones de operación relacionadas proporcionadas por CMSIS.

imagen-20230621235805628

El parámetro init es el número de milisegundos entre interrupciones. timer_set_callback() va seguido de una función que se puede definir por sí misma, de modo que la función se ejecuta cuando se activa la interrupción del temporizador. El código anterior significa que la luz LED cambia cada 100 ms y la CPU se encuentra en un estado de bajo consumo de energía en condiciones normales.

2C

Esquema de transmisión para conectar múltiples módulos: I2C, utilizando dos buses.

imagen-20230622000302459

Los dos buses son el bus de reloj SCL y el bus de datos SDA.

Proceso de comunicación

Ahora veamos el proceso de enviar un mensaje de un módulo (maestro) a otro módulo (esclavo) en I2C.

1687363434463

  1. La MCU utiliza un determinado método para identificarse a sí misma para iniciar la transmisión.
  2. La MCU envía la dirección del esclavo LCD + un bit de lectura y escritura, y otros módulos la reciben y descubren que la dirección no es la suya, por lo que no la procesan.
  3. Después de que LCD lo recibe, sabe que el objetivo es él mismo, por lo que devuelve un acuse de recibo.
  4. MCU envía un marco de datos después de recibir ACK.
  5. Después del envío, la MCU espera el ACK y continúa enviando la siguiente trama de datos después de recibir el ACK.
  6. Enviar hasta el final del envío de parada de bit de parada.

imagen-20230622000920336

La longitud de los datos se puede configurar, como 789.

Los dispositivos en el bus se comunican semidúplex con salidas de drenaje abierto.

imagen-20230713135505107

La resistencia pull-up eleva el bus predeterminado.

Cuando la salida del dispositivo es baja, el bus se conecta a tierra y el bus se baja (el bus completo se baja). El ejemplo dado por el Sr. Jiangxie Science and Technology es muy bueno. Es como un travesaño en un autobús. Alguien tira del travesaño y lo tira hacia abajo. Todo el travesaño se tira hacia abajo. Bajo, alguien está usando el autobús".

Luego está la forma en que el bus transmite los datos ¿Bajo qué circunstancias los dos buses de SCL y SDA indican start stop 0 1 bit?

imagen-20230713140225426

En primer lugar, el valor de SDA solo es significativo cuando SCL es de alto nivel.

SDA es de mayor a menor, lo que indica el bit de inicio. De menor a mayor, indica el bit de parada.

Después del bit de inicio, el nivel alto de SDA significa 1, el nivel bajo significa 0.

Después de enviar datos de 1 byte, el bus sigue subiendo. Si el receptor baja el bus y el remitente encuentra que el bus es 1 → 0 (no tirado por el mismo remitente, el receptor lo bajó por él, pero el remitente puede detectarlo), significa que el receptor ha recibido con éxito y tiró Tire del autobús para mostrar "recibido". Si SDA todavía está en un nivel alto, significa que el receptor no ha recibido o enviado correctamente el ACK.

imagen-20230713140822834

resolución de problemas

I2C es un protocolo de comunicación maestro-esclavo muy simple, pero tiene muchas limitaciones. Por ejemplo, la línea de dirección de 7 bits solo permite 2^7 dispositivos; como máximo dos dispositivos se comunican maestro-esclavo a la vez; la velocidad de un dispositivo afectará la comunicación de todo el bus, etc.

Pregunta 1: ¿Qué debo hacer si la velocidad de procesamiento del dispositivo esclavo es demasiado lenta para recibir nuevos marcos de datos en el próximo ciclo de reloj?

Método: estiramiento del reloj, tirando hacia abajo de SCL durante un período de tiempo para fingir que el próximo ciclo de reloj aún no ha llegado.

imagen-20230713141906054

Pregunta 2: ¿Qué debo hacer si varios dispositivos envían conflictos de datos al mismo tiempo?

Método: Arbitación de bus, sabemos que el bus es derribado por un dispositivo, y todos los dispositivos pueden recibir la señal de que el bus es derribado. Por lo tanto, si dos dispositivos comienzan a enviar información al mismo tiempo, no importa si los datos anteriores son consistentes, cuando los datos son inconsistentes por primera vez, un dispositivo envía datos 0 y el otro envía datos 1. En este momento , el bus SDA es derribado por 0 de DATA2.

imagen-20230713142029471

El dispositivo que envía datos DATA1 entenderá: alguien está enviando datos conmigo al mismo tiempo, por lo que el bus no es 1 como esperaba, pero él lo reduce a 0. Entonces renuncio, tú lo envías. Luego solo quedan los datos enviados por DATA2.

Pregunta 3: Los datos enviados arriba son de 1 byte y 8 bits cada vez, lo cual es correcto. ¿Qué pasa si la dirección a enviar no es de 8 bits?

Método: menos de 8 bits se llenan con algunos bits de inicio adicionales fijos, las direcciones de más de 8 bits se llenan con dos bytes y las que no son suficientes también se llenan con bits de inicio adicionales.

imagen-20230713143052018

Pregunta 3: Si mi maestro termina de enviar datos y quiere recibir datos inmediatamente y convertirse en esclavo, ¿es factible?

Método: Reenviar el bit de inicio a través de una señal sr, es decir, repetir inicio, para identificarse como lectura en lugar de escritura, y reiniciar la comunicación.

imagen-20230713143601570

formato de direccionamiento

Hay algunos formatos fijos para el direccionamiento de direcciones esclavas.

imagen-20230713143744619

0000 000 0: Transmitir, hablar con todos los nodos esclavos. Si el esclavo ignora (NACK), no participará en la transmisión. Participó si se devuelve ACK. Sin embargo, si varios esclavos devuelven ACK, el maestro no sabe quién respondió.

El segundo byte envía algún comportamiento relacionado, como: iniciar, borrar, restablecer software

aplicación de programación

modo esclavo:

  • Los dispositivos I2C funcionan en modo esclavo por defecto.
  • Los relojes periféricos se programan en el registro I2C_CR2. La frecuencia está entre 2kHz~100kHz.
  • El hardware espera automáticamente el envío de la información de inicio y dirección.
  • Si la información de la dirección es la misma que la almacenada en OAR1, significa que el objetivo es él mismo. Si el bit ACK es 1, envíe un pulso de reconocimiento.
  • Configure el bit ADDR, 1 significa coincidencia.
  • Si ITEVFEN es el indicador de evento de interrupción es 1, se genera una interrupción.
  • El bit TRA indica si el esclavo está en modo R o T (recepción o transmisión).
  • La marca de bit BTF ha sido confiscada.

1689255491311

imagen-20230713214410998

Todavía es un poco confuso decirlo. ¿Qué pasó exactamente por I2C para enviar datos sin problemas?

En primer lugar, a partir del concepto de modo principal. El modo maestro maestro impulsa la señal del reloj e inicia la transferencia; el modo esclavo esclavo responde a la transferencia.

modo principal

Diagrama de secuencia de transferencia I2C para datos maestros de envío

enviar:

Todos los eventos EV bajan el SCL hasta que se ejecuta la secuencia de software correspondiente.

S: evento de inicio. Por ejemplo, configure el reloj periférico en el registro CR2, configure el registro del reloj, eleve el registro del reloj, habilite CR1 para habilitar el reloj, configure el bit de inicio en CR1, espere a que el bus baje para indicar que está listo, envíe el señal de inicio y cambiar al modo principal.

EV5: Inicie el evento con éxito, configure el registro SB = 1. Solo después de que el registro SB = 1 se puede realizar la fase de dirección, y los eventos SB y EV5 se borrarán automáticamente después de que se ejecute la fase de dirección.

Dirección: etapa de dirección. Transmita la dirección de 7 bits + 1 bit de lectura y escritura y luego espere el reconocimiento del esclavo. Reciba confirmación e ingrese EV6.

EV6: Establecer el bit de dirección = 1 significa que la fase de dirección se ejecuta con éxito y el maestro ha recibido el acuse de recibo. Ingrese automáticamente EV8 después de borrar EV6.

EV8: configure TxE y prepárese para escribir los datos que enviará el host. TxE indica que el registro de datos está vacío y se puede escribir. Cada vez que se escriben datos en DR, los eventos TxE y EV8 se borrarán. Después de escribir los datos, los datos se transmiten y el host continúa transmitiendo después de recibir el acuse de recibo. Utilice BTF=1 para indicar el final de la transferencia de datos.

void i2c_write(uint8_t address, uint8_t *buffer, int buff_len) {
    
    
	int i = 0;
    // Send in sequence: Start bit, Contents of buffer 0..buff_len, Stop
    while (((I2C1->SR2>>1)&1)); // wait until I2C1 is not busy anymore
    I2C_GenerateSTART(I2C1, ENABLE); // Send I2C1 START condition
    // wait for I2C1 EV5 --> Slave has acknowledged start condition
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
    // Send slave Address for write then wait for EV6
    I2C_Send7bitAddress(I2C1, address, I2C_Direction_Transmitter);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    while (i < buff_len){
    
    
        I2C_SendData(I2C1, buffer[i]); // send data then wait for EV8_2
        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
        i++;
    }
    I2C_GenerateSTOP(I2C1, ENABLE); // send stop bit
}

imagen-20230714110003657

tomar el control:

El frente es el mismo que el maestro transmite.

TxE se ha cambiado a RxE y =1 indica que se han recibido datos.

Después de que el maestro establece el evento de parada (envía NACK), deja de recibir.

void i2c_read(uint8_t address, uint8_t *buffer, int buff_len) {
    
    
    int i = 0;
    // Start bit, Contents of buffer from 0..buff_len, sending a NACK
    // for the last item and an ACK otherwise, Stop bit
    I2C_GenerateSTART(I2C1, ENABLE);
    while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); //EV5
    // Send slave Address for write then wait for EV6
    I2C_Send7bitAddress(I2C1, address, I2C_Direction_Receiver);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
    I2C_AcknowledgeConfig(I2C1, ENABLE); // going to send ACK
    while (i < buff_len - 1){
    
    
        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); //EV7
        buffer[i] = I2C_ReceiveData(I2C1); // get data byte
        i++;
    }
    I2C_AcknowledgeConfig(I2C1, DISABLE); // going to send NACK
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)); //EV7
    buffer[i] = I2C_ReceiveData(I2C1); // get the last byte
    I2C_GenerateSTOP(I2C1, ENABLE); // send stop
}

modo esclavo

1689259086166

enviar:

inicio El evento de inicio lo inicia el maestro. El esclavo comprueba la dirección y decide si envía un bit de confirmación.

EV1: establecer el bit addr indica una coincidencia de dirección.

EV3-1: establece el bit TxE e inicia los datos entrantes. Hasta que el host devuelve NACK para indicar que no quiere más datos, o AF=1 indica que el acuse de recibo falla.

1689259113895

tomar el control:

El frente a EV1 y la transmisión esclava son iguales.

  1. Los datos se leen del registro DR.
  2. Después de leer un byte, si se ha establecido el bit de confirmación, devuelve la información de confirmación.
  3. El bit RxE es el registro de estado de los datos recibidos.
  4. Detener cuando el maestro genera una condición de parada.

situación anormal:

Error de bus, NACK, falla de arbitraje, tiempo de espera de excepción de reloj.

imagen-20230714110916968

Supongo que te gusta

Origin blog.csdn.net/jtwqwq/article/details/131719696
Recomendado
Clasificación