Olá amigos!Nikolay está com você novamente, no último artigo "
DevBoy - como eu criei um projeto de dispositivo de código aberto e lancei um projeto no Kickstarter ", a ênfase estava mais na aparência e no hardware, hoje falaremos sobre como isso é feito "
dentro " e analisaremos a parte do software.

Quem se importa - peço um gato.
Como mencionado anteriormente, o projeto é baseado no microcontrolador
STM32F415RG da STMicroelectronics no núcleo ARM Cortex-M4. Existem vários IDEs diferentes para o desenvolvimento de microcontroladores para esses microcontroladores, no entanto, para um projeto de código aberto, você precisa de pelo menos um IDE livre e, de preferência, de código aberto. Além disso, o IDE ainda deve ser suportado no
STM32CubeMX . No momento em que comecei a trabalhar neste projeto, havia apenas um IDE que atendia a todos esses requisitos -
System Workbench for STM32 .
No momento, existe o Atollic TrueStudio, que se tornou gratuito depois que a STMicroelectronics os comprou.
O próximo programa usado é o
STM32CubeMX . Este programa é um utilitário para configurar os periféricos do microcontrolador usando uma interface gráfica.

O resultado é um código que inclui a HRAW (HAL). Muitos programadores realmente não gostam dessa "
criação ", não é sem bugs, mas, no entanto, simplificam muito o desenvolvimento e melhoram a portabilidade de programas entre diferentes microcontroladores da STMicroelectronics.
Além disso, durante a configuração, você pode especificar o uso de alguns softwares de código aberto de terceiros, como
FreeRTOS ,
FatFS e outros.
Terminamos a descrição do software usado, agora vamos para a parte mais interessante - o
DevCore . O nome vem do "
Core Development ", vamos em ordem.
Primeiro de tudo, é o
C ++ RTOS Wrapper (
neste caso, o FreeRTOS ). O Vrapper é necessário por dois motivos:
- É muito melhor criar um objeto e, em seguida, chamar mutex.Take (), por exemplo, do que criar um identificador, chamar a função create e, em seguida, passar esse identificador para todas as funções mutex
- Se for necessário substituir o RTOS, basta substituir o wrapper e nem todas as chamadas para funções RTOS do código
Não faz sentido trazer o código do invólucro aqui, quem se importa -
olhamos para o GitHub e seguimos em frente.
A próxima parte é o
Application Framework . Esta é a classe base para todas as tarefas. Como esses são apenas dois arquivos relativamente pequenos, faz sentido listá-los completamente:
Classes herdadas podem substituir 4 funções virtuais:
- Setup () é uma função chamada antes de iniciar uma tarefa. A conclusão do código é garantida em todas essas funções de todas as tarefas antes da execução dos ciclos principais.
- Loop () - o principal ciclo de tarefas, onde a tarefa em si organiza o que deseja. Não pode ser usado em conjunto com as duas funções a seguir.
- TimerExpired () - uma função chamada periodicamente com um determinado intervalo. Conveniente para implementar a pesquisa de um sensor, por exemplo.
- ProcessMessage () - função para processar mensagens de outras tarefas.
As duas primeiras funções implementam o "
estilo Arduino " para tarefas.
Os próximos dois implementam o sistema "
evento ", simplificando a interação das tarefas. Com essa abordagem, a tarefa implementa uma interface externa na forma de funções que enviam dados de envio para a tarefa por meio de uma caixa de correio interna. Com essa abordagem, o usuário que usa essa interface não precisa se preocupar em que contexto as ações são executadas. É verdade que isso é possível apenas para levantadores ou equipes. Para getters, é melhor usar mutexes e cópia de dados para evitar a captura de mutex por um longo tempo.
Essa abordagem foi identificada quando eu estava desenvolvendo software para equipamentos médicos. O microcontrolador tem um
cão de guarda e
, no caso de muitas tarefas, você precisa acompanhar todas elas. Para isso, havia uma tarefa separada que atendia ao watchdog e recebia mensagens de outras tarefas enviadas da função TimerExpired (). Se durante o período de tempo da tarefa * n não houve mensagens, a tarefa morreu,
apagamos a luz e tomamos medidas para desligar todas as glândulas que afetam o paciente.
Todas as tarefas são únicas, não é possível criá-las diretamente, mas é possível obter um link para a tarefa. Para fazer isso, cada tarefa implementa o método estático
GetInstance () :
Também estão incluídas tarefas para
saída de áudio ,
módulos de entrada e
manutenção da tela.A tarefa
de saída de som é bastante simples - ela recebe uma série de frequências e durações e simplesmente altera periodicamente as configurações do temporizador para gerar pulsos retangulares de uma determinada frequência.
A tarefa de manutenção
dos módulos de água também
é bastante simples. Dos pontos interessantes, o módulo é detectado automaticamente: primeiro, usando o ADC, medimos a tensão, se estiver na faixa de 25% a 75% da tensão de alimentação, um joystick analógico é inserido, caso contrário, botões ou um codificador. Se não for um joystick, verifique a quarta linha do módulo de E / S: se estiver em um nível alto, esses são os botões (
todos os botões são puxados para cima e, quando os botões são pressionados, estão fechados no chão ), se estiver baixo, é um codificador (um
pequeno botão é "pressionado" no chão e quando pressionado fecha para poder ).
A tarefa de manutenção da tela é a tarefa mais interessante. Para começar, a tela tem 320x240x16bit, portanto, você precisa de 153600 bytes para o buffer de quadros . Isso não é apenas muito, é simplesmente enorme - neste microcontrolador há apenas 192k de RAM e, nos microcontroladores, pode ser mais fácil não ter o tamanho certo. Como ser A resposta é simples: desenhe a tela em partes! Mas você pode desenhar algo de maneiras diferentes ...A solução que eu apliquei para esta tarefa é como tudo engenhoso. Possui um buffer em duas linhas da tela. Em uma linha, desenhamos tudo o que deveria ser, enviamos para a tela via SPI no modo DMA e, neste momento, podemos preparar outra linha.Como a tarefa sabe o que deve estar na linha e como desenhá-la? Mas ela não sabe!Mas ela tem uma lista de objetos que sabem como se desenhar. Cada um desses objetos é herdado da classe VisObject .DrawInBufW() , , (
«» ). .
, — . Action() .
, (
, , ), (
).
DevCore UI(
), I2C, I2C BME280 EEPROM 24256, — .
GitHub :
https://github.com/nickshl/devboyPS , Epic Fail'. , - "
", 180 , (
, ! ) .
— . — …