Hola, entiendo que se trata de un motor de escobillas con encoder incorporado.
Ahi vas a necesitar 4 funciones principales dentro del bucle del main:
while(1) {
- Lectura de pulsadores para ajustar la velocidad (Vset).
- Lectura del régimen actual (mediante interrupcion).
- Ajuste del dutty cicle del PWM si es necesario.
- Feedback.
}
La lectura de pulsadores ningún problema, if (!p+) rpm++; if(!p-) rpm-- o similar, como lo quieras ajustar y le pones alguna rutina antirrebote.
Para la lectura del régimen de giro actual necesitas usar un timer, y una variable inicializada a cero para almacenar el numero de veces que desborda ese timer. conectas el encoder a un pin que tenga interrupción por cambio de estado.
Cuando se produzca un cambio de estado entras en la interrupción y:
1- Lees el estado actual del pin y te mantienes en espera de que cambie de nuevo.
2- Una vez ha cambiado, pones el timer a cero y vigilas dos cosas:
2-1: La bandera tmrxxif (que indica que el timer ha desbordado), entonces incrementas el contador y bajas la bandera, nada mas.
2-2: Control de timeout: ¿Cuanto tiempo máximo esperarás cambio de estado antes de abandonar?, si el motor se detiene el programa quedaría atrapado esperando cambios de estado, si eso no interesa, y no creo que interese, aqui debes esperar lo que creas conveniente. Como tieness un contador de desbordamientos, y sabes el tiempo que tarda el timer en desbordar (depende del oscilador, preescalador, postcalador, etc) sabes con qué valor de contador abandonas.
3- Esperas otros dos cambios de estado. En todos ellos haces lo mismo descrito en 2-1 y 2-2.
- Una vez alcanzado el ultimo cambio de estado:
- lees el valor del timer.
- Lees el valor del contador de desbordamientos. Si es un timer de 16 bits desborda a las 65535 + 1 pulsos de conteo. De 8 bits desborda a los 255 + 1 pulso de conteo.
la operacion para periodo es:
periodo = numero de desbordamientos * (65535 + 1);
periodo += valor del timer obtenido al momento del ultimo cambio de estado del pin.
Todo esto es para UN SOLO DIENTE del encoder. Ahora bien, o repites lo anterior tantas veces como dientes tenga el encoder y vas acumulando las lecturas y aplicar la operación del periodo a todo, o.... Lo haces para un solo diente y el resultado lo multiplicas por el numero de dientes del encoder (No merece la pena, ya puestos..... mejor medirlo todo), solo tienes que encerrar todo lo anterior (excepto el calculo del periodo) en un while(){} cuya condicion sea while (numero_de_dientes-- > 0) { }
De una manera u otra, una vez que tienes un periodo, lo conviertes en su tiempo equivalente. Como sabes el tiempo que tarda el timer en incrementarse y en desbordarse por que lo has calculado dependiendo del oscilador, prescaler, postcaler y poco más, puedes saber cuanto tiempo ha tardado el motor en dar un giro completo.
Le aplicas la inversa y ya tienes la frecuencia.
La divides entre 60 y ya tienes las rpm, aunque yo aun lo trabajaría en frecuencia. Las rpm solo para mostrarlas si hace falta.
Ya solo queda el bloque de feedback, que consiste en comparar el valor de rpm ajustado (Vset) con el obtenido, si es mayor, bajamos el dutty cicle al pwm, si es menor, subimos el dutty cicle al pwm... Esto es lo mas facil, pero no es lo mejor.
Para bordarlo ya mejor implementar un algoritmo PID que no es muy complicado y te dará un redondeo de ajuste y suavidad que quitan el sentido....

Un saludo.