Итак берем от STM32 один ADC, в stm32f103 их 2 точно есть, поэтому очень хороший задел на будущее.
Используем 1-й канал, 1-го ADC.
В начале кода выбор управляющих пинов для дисплея, типа D/C или CS, которыми будем управлять в ручную, но SPI будет аппаратный. Дисплей пока от nokia 5110, имеет довольно низкое разрешение 84х48, да еще и медленный, т.е. на максимальную скорость SPI запустить не получится. Инетерсный факт, что на всем семействе STM32 частота SPI делится от 48MHz, а на STM32F10x делится системная частота, т.е. на камешке STM32F103 делится 72MHz, от чего получается очень быстрый SPI - ну опровергнуть или подтвердить не могу, т.к. нет соответствующих приборов для измерения, работает и ладно.
Код: Выделить всё
#include "stm32f10x.h"
#include "font.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define SCK_Pin GPIO_Pin_5
#define SCK_Pin_Port GPIOA
#define MOSI_Pin GPIO_Pin_7
#define MOSI_Pin_Port GPIOA
#define DC_Pin GPIO_Pin_7
#define DC_Pin_Port GPIOB
#define RST_Pin GPIO_Pin_5
#define RST_Pin_Port GPIOB
#define SS_Pin GPIO_Pin_6
#define SS_Pin_Port GPIOB
#define LCDHeight 48
#define LCDWidth 84
#define BuffSize (LCDWidth*LCDHeight/8)
#define swap(a, b) { int16_t t = a; a = b; b = t; }
volatile __IO uint32_t TimingDelay;
volatile __IO uint32_t UserTimingDelay=0;
void Delay(__IO uint32_t nTime)
{
TimingDelay = nTime;
while(TimingDelay != 0);
}
/* wait busy loop, microseconds */
void delay_us( uint16_t uSecs )
{
volatile uint16_t counter=1; // Погрешность в 1мкСекунду
TIM_Cmd(TIM2,ENABLE);
TIM_SetCounter(TIM2,counter);
while(counter<uSecs)
{
counter=TIM_GetCounter(TIM2);
}
TIM_Cmd(TIM2,DISABLE);
}
void ResetOn() {
GPIO_SetBits(RST_Pin_Port, RST_Pin);
}
void ResetOff() {
GPIO_ResetBits(RST_Pin_Port, RST_Pin);
}
void DCOn() {
GPIO_SetBits(DC_Pin_Port, DC_Pin);
}
void DCOff() {
GPIO_ResetBits(DC_Pin_Port, DC_Pin);
}
void SSOff() {
GPIO_ResetBits(SS_Pin_Port, SS_Pin);
}
void SSOn() {
GPIO_SetBits(SS_Pin_Port, SS_Pin);
}
void SPISend(uint8_t data) {
SPI_I2S_SendData(SPI1, data); // отправили данные
while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); // ждём, пока данные не отправятся
}
uint8_t picture[BuffSize] = // изначально дисплей 102х65, а у меня 84х48, лишнее комментиуем
{
//0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0xc0, 0xf0, 0xfc,
0xfa, 0xf6, 0xe6, 0xee, 0xce, 0xde, 0xfe, 0xbf,
0xbf, 0xff, 0x7f, 0x7f, 0xff, 0xfe, 0xfe, 0xfe,
0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xf8,
0xf8, 0xf8, 0xf8, 0xf0, 0xf0, 0xf0, 0xf0, 0xe0,
0xe0, 0xe0, 0xe0, 0xc0, 0x40, 0x40, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, //0x0, 0x0, 0x0, 0x0,
//0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
//0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x00, //0x30,
0x78, 0xfc, 0xfc, 0xfe, 0xfe, 0xfe, 0xfe, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xe0, 0xc0, 0x8e, 0xbf, 0xbf, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe,
0xff, 0xff, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd,
0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd,
0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc,
0x3c, 0x1e, 0xe, 0x2, 0x0, 0x0, 0x80, 0x80,
0x80, 0x80, 0x0, //0x0, //0x0, 0x0, 0x0, 0x0,
//0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
//0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0,
0x1, 0x1, 0x3, 0x3, 0x7, 0x7, 0xf, 0xf,
0xf, 0x1f, 0x1f, 0x1f, 0x1f, 0x3f, 0x3f, 0x3f,
0x3f, 0x7f, 0x7f, 0x7f, 0x7f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xee, 0xe4,
0xf0, 0xf0, 0xf0, 0xf8, 0xff, 0xff, 0xff, 0xff,
0xff, //0xff, 0xff, 0xff, //0xff, 0xfe, 0xfe, 0xfe,
//0xfc, 0xfc, 0xfc, 0xf8, 0xf8, 0xf8, 0xf0, 0xf0,
//0xe0, 0xe0, 0xc0,
0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x2, 0x19, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf,
0xf, 0xf, 0x1f, 0x1f, 0xdf, 0xff, 0xff, 0xff,
0xff, 0x7f, 0x7f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
0x3f, 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0xcf, 0x1f,
0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, //0x1f,
//0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0xf,
//0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x7, 0x7, 0x3,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x70,
0xf8, 0xfc, 0xfc, 0xfc, 0x3e, 0xe, 0x6, 0x2,
0x87, 0xff, 0xdf, 0x3f, 0x7f, 0x7f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x7, 0x7, 0xf, 0xf, 0xc,
0xf8, 0xf8, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0,
0xe0, 0xf0, 0x30, 0x20, 0x20, 0x80, 0xc0, 0xc0,
0xc0, 0xc0, 0xc4, 0xcc, 0xcc, 0xcc, 0xd8, 0xf8,
0xf8, 0xf8, 0x38, 0x8, 0xd, 0xf, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, //0x0, 0x0, 0x0,
//0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
//0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x7,
0xf, 0x3f, 0x7f, 0xfc, 0xf8, 0xf0, 0xe0, 0xc7,
0x8f, 0x8f, 0x1e, 0x1c, 0x38, 0x30, 0x31, 0x21,
0x63, 0x63, 0x47, 0x47, 0x4f, 0x4f, 0x9f, 0x9f,
0x9f, 0xbf, 0x3f, 0x3f, 0x7f, 0x7f, 0x7f, 0xff,
0xff, 0xfc, 0xfc, 0xf8, 0xf8, 0xf0, 0xff, 0xff,
0xf0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0x83, 0x81,
0x81, 0x80, 0x80, 0x80, 0x0, 0x2, 0x86, 0x86,
0xc2, 0xc0, 0xc0, 0xfc, 0xfc, 0xfc, 0x74, 0x77,
0x33, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80,
0xc0, 0x0, 0x0, //0x0, 0x0, 0x0, 0x0, 0x0,
//0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
//0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
//0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x3, 0x7, 0x7, 0x7, 0xf, 0xe, 0xe, 0xe, 0xe, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x3c, 0x38, 0x38, 0x38, 0x38, 0x38, 0x39, 0xf9, 0xf9, 0x78, 0x38, 0x10, 0x10, 0x13, 0x31, 0x31, 0x31, 0x31, 0x31, 0x33, 0x33, 0xbf, 0xfd, 0x69, 0x1, 0x43, 0x43, 0x43, 0xe3, 0xf7, 0x9f, 0x83, 0x1, 0x9, 0x19, 0x10, 0x30, 0x60, 0xe0, 0xc0, 0x4, 0x4, 0x4, 0x4, 0x6, 0x6, 0x6, 0x7, 0x3, 0x3, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0xff, 0x60, 0x30, 0x30, 0x30, 0x18, 0x18, 0x30, 0x18, 0x1c, 0xc, 0xe, 0x7, 0x3, 0x3, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x3, 0x2, 0x6, 0x6, 0x4, 0xc, 0xf, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
};
void LCD_clear() {
uint16_t i;
DCOn();
for(i = 0; i < BuffSize; i++) SPISend(0);
Delay(1);
DCOff();
SPISend(0x00);
}
void LCDInit(void) {
ResetOff(); //Set LCD reset = 0;
DCOn(); //Mode = command;
SSOn(); //Unselect chip;
//Keep reset pin low for 10 ms
Delay(10);
//Release Reset Pin
ResetOn(); //LCD_RST = 1;
SSOff();
DCOff();
//Configure LCD module
SPISend(0x21); //Extended instruction set selected Режим настроек
SPISend(0xC0); //Set LCD voltage (defined by experimentation...) Контраст!
SPISend(0x13); //Set Bias for 1/48
//SPISend(0x06); //Set temperature control (TC2) Необязательно
SPISend(0x20); //Revert to standard instruction set
SPISend(0x0c); //Set display on in "normal" mode (not inversed) Режим отображения
}
void LCD_set_XY(unsigned char X, unsigned char Y) {
unsigned char x;
x = 6 * X;
DCOff();
SPISend(0x80 | x);
SPISend(0x40 | Y);
Delay(1); // Задержка, чтобы успела примениться последняя команда
DCOn(); // Принуждает выполнить последнюю команду
}
void LCD_write_char(unsigned char c) {
unsigned char line;
unsigned char ch = 0;
c = c - 32;
DCOn();
for (line = 0; line < 6; line++) {
ch = font6_8[c][line];
SPISend(ch);
}
Delay(1); // Чтобы применился последний байт необходима задержка и пустая команда
DCOff(); // При использования HW SPI данные действия обязательны, т.к. последний бит должен быть передан при переключении D/C
SPISend(0x00); // Пустая команда
Delay(1); // Задержка, чтобы команда была отработана
}
void LCD_write_string(char *s) {
unsigned char ch;
while (*s != '\0') {
ch = *s;
LCD_write_char(ch);
s++;
}
}
void LCD_Write_Dec(unsigned int b) {
unsigned char datas[3];
datas[0] = b / 1000;
b = b - datas[0] * 1000;
datas[1] = b / 100;
b = b - datas[1] * 100;
datas[2] = b / 10;
b = b - datas[2] * 10;
datas[3] = b;
datas[0] += 48;
datas[1] += 48;
datas[2] += 48;
datas[3] += 48;
LCD_write_char(datas[0]);
LCD_write_char(datas[1]);
LCD_write_char(datas[2]);
LCD_write_char(datas[3]);
}
void LCDisplay(){
LCD_set_XY(0,0);
//Включаем режим данных и заливаем катинку
DCOn();
uint16_t i;
for(i = 0; i < BuffSize; i++) SPISend(picture[i]);
Delay(1); // Задержка и пустая команда, чтобы применился последний байт данных
DCOff();
SPISend(0x00);
}
void DispClear(){
uint16_t i;
for(i = 0; i < BuffSize; i++) picture[i]=0;
}
void DispSetPixel(int16_t x, int16_t y, uint16_t color){
if(x<0)x=0;
if(y<0)y=0;
if(x>=LCDWidth) x = LCDWidth-1;
if(y>=LCDHeight) y = LCDHeight-1;
if(color){
picture[(y/8)*LCDWidth+x] |= 1<<(y%8);
}else{
picture[(y/8)*LCDWidth+x] &= ~1<<(y%8);
}
}
void drawLine(int16_t x0, int16_t y0,
int16_t x1, int16_t y1,
uint16_t color) {
int16_t steep = abs(y1 - y0) > abs(x1 - x0);
if (steep) {
swap(x0, y0);
swap(x1, y1);
}
if (x0 > x1) {
swap(x0, x1);
swap(y0, y1);
}
int16_t dx, dy;
dx = x1 - x0;
dy = abs(y1 - y0);
int16_t err = dx / 2;
int16_t ystep;
if (y0 < y1) {
ystep = 1;
} else {
ystep = -1;
}
for (; x0<=x1; x0++) {
if (steep) {
DispSetPixel(y0, x0, color);
} else {
DispSetPixel(x0, y0, color);
}
err -= dy;
if (err < 0) {
y0 += ystep;
err += dx;
}
}
}
void interfaceINIT(void){
// Включаем RCC_APB2Periph_AFIO модуль альтернативной функции, чтобы отключить JTAG и освободить PB4
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_SPI1, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); // Отключаем JTAG
GPIO_InitTypeDef PORT;
// выбрали ноги для настройки
PORT.GPIO_Pin = SCK_Pin | MOSI_Pin;
// установили наименьшую скорость (максимальная скорость контроллера 4 Мбита в секунду)
PORT.GPIO_Speed = GPIO_Speed_50MHz;
// (важно!) определяем предназначение ног. здесь - выбор "альтернативной функции" ног
PORT.GPIO_Mode = GPIO_Mode_AF_PP;
// настроили ноги в порту А
GPIO_Init(GPIOA, &PORT);
// выбрали ноги для настройки
PORT.GPIO_Pin = DC_Pin | RST_Pin | SS_Pin | GPIO_Pin_4;
// установили скорость (тут - без разницы)
PORT.GPIO_Speed = GPIO_Speed_50MHz;
// предназначение - общее, выход
PORT.GPIO_Mode = GPIO_Mode_Out_PP;
// настроили ноги в порту B
GPIO_Init(GPIOB, &PORT);
SPI_InitTypeDef SPIConf;
// указываем, что используем мы только передачу данных
SPIConf.SPI_Direction = SPI_Direction_1Line_Tx;
// указываем, что наше устройство - Master
SPIConf.SPI_Mode = SPI_Mode_Master;
// передавать будем по 8 бит (=1 байт)
SPIConf.SPI_DataSize = SPI_DataSize_8b;
// режим 00
SPIConf.SPI_CPOL = SPI_CPOL_Low;
SPIConf.SPI_CPHA = SPI_CPHA_1Edge;
SPIConf.SPI_NSS = SPI_NSS_Soft;
// установим скорость передачи. Быстрее чем при делителе на 8 не заводится
SPIConf.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
// передаём данные старшим битом вперёд (т.е. слева направо)
SPIConf.SPI_FirstBit = SPI_FirstBit_MSB;
// внесём настройки в SPI
SPI_Init(SPI1, &SPIConf);
// включим SPI1
SPI_Cmd(SPI1, ENABLE);
// SS = 1
SPI_NSSInternalSoftwareConfig(SPI1, SPI_NSSInternalSoft_Set);
ADC_InitTypeDef ADC_InitStructure;
RCC_ADCCLKConfig(RCC_PCLK2_Div2);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
ADC_DeInit(ADC1);
ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode=DISABLE;
ADC_InitStructure.ADC_ScanConvMode=DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel=1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
RCC_ClocksTypeDef RCC_Clocks;
RCC_GetClocksFreq(&RCC_Clocks);
SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000); //Таймер для функции Delay, срабатывает раз Милисекунду.
/* Enable timer clock - use TIMER5 */
TIM_TimeBaseInitTypeDef Tim2;
//TIM_DeInit(TIM5);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
Tim2.TIM_Period=0xFFFF;
Tim2.TIM_Prescaler=(RCC_Clocks.HCLK_Frequency / 1000000)-1;
Tim2.TIM_ClockDivision=TIM_CKD_DIV1;
Tim2.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2,&Tim2);
}
uint16_t readADC1(uint8_t channel){
ADC_RegularChannelConfig(ADC1,channel, 1, ADC_SampleTime_1Cycles5);
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)==RESET);
return ADC_GetConversionValue(ADC1);
}
//Далее осциллограф
// Variables you might want to play with
uint8_t useThreshold = 1; // 0 = Off, 1 = Rising, 2 = Falling
uint8_t theThreshold = 80; // 0-255, Multiplied by voltageConst
unsigned int timePeriod = 200; // 0-65535, us or ms per measurement (max 0.065s or 65.535s)
uint8_t voltageRange = 1; // 1 = 0-3.3V, 2 = 0-1.65V, 3 = 0-0.825V
uint8_t ledBacklight = 100;
uint8_t autoHScale = 1; // Automatic horizontal (time) scaling
uint8_t linesNotDots = 1; // Draw lines between data points
// Variables that can probably be left alone
#define numOfSamples 84 // Leave at 100 for 128x64 pixel display
const uint8_t vTextShift = 65; // Vertical text shift (to vertically align info)
const uint8_t vScale = 39; // 40-1 (0..39)
const uint32_t ADCScale = 4096;
float ScaleConst = 0;
uint32_t HQadcReadings[numOfSamples];
uint8_t adcReadings[numOfSamples];
//uint8_t adcOldReadings[numOfSamples];
uint8_t thresLocation = 0; // Threshold bar location
float voltageConst = 0.052381; // Scaling factor for converting 0-63 to V
float avgV = 0.0;
float maxV = 0.0;
float minV = 0.0;
float ptopV = 0.0;
float theFreq = 0;
void collectData(void) {
unsigned int tempThres = 0;
unsigned int i = 0;
if (autoHScale) {
// With automatic horizontal (time) scaling enabled,
// scale quickly if the threshold location is far, then slow down
if (thresLocation > 5*numOfSamples/8) {
timePeriod = timePeriod + 10;
} else if (thresLocation < 3*numOfSamples/8) {
timePeriod = (timePeriod>10?timePeriod - 10:0);
} else if (thresLocation > numOfSamples/2+1) {
timePeriod = timePeriod + 2;
} else if (thresLocation < numOfSamples/2-1) {
timePeriod = (timePeriod>2?timePeriod - 2:0);
}
}
// Enforce minimum time periods
/* if (timePeriod < 10) {
timePeriod = 10;
}*/
// Adjust voltage contstant to fit the voltage range
/* if (voltageRange == 1) {
voltageConst = 0.0523810; // 0-3.30V
} else if (voltageRange == 2) {
voltageConst = 0.0261905; // 0-1.65V
} else if (voltageRange == 3) {
voltageConst = 0.0130952; //0-0.825V
}*/
// If using threshold, wait until it has been reached
if (voltageRange == 1) tempThres = theThreshold * 25; //<<2
else if (voltageRange == 2) tempThres = theThreshold << 1;
else if (voltageRange == 3) tempThres = theThreshold;
if (useThreshold == 1) {
i = 0; while ((readADC1(ADC_Channel_0)>tempThres) && (i<32768)) i++;
i = 0; while ((readADC1(ADC_Channel_0)<tempThres) && (i<32768)) i++;
}
else if (useThreshold == 2) {
i = 0; while ((readADC1(ADC_Channel_0)<tempThres) && (i<32768)) i++;
i = 0; while ((readADC1(ADC_Channel_0)>tempThres) && (i<32768)) i++;
}
// Collect ADC readings
for (i=0; i<numOfSamples; i++) {
// Takes 35 us with high speed ADC setting
HQadcReadings[i] = readADC1(ADC_Channel_0);
if (timePeriod > 0)
delay_us(timePeriod);
}
for (i=0; i<numOfSamples; i++) {
// Scale the readings to 0-vScale and clip to vScale if they are out of range.
if (voltageRange == 1) {
/*if (HQadcReadings[i]>>4 < 0b111111) adcReadings[i] = HQadcReadings[i]>>4 & 0b111111;
else adcReadings[i] = 0b111111;*/
adcReadings[i] = HQadcReadings[i]*ScaleConst;
} else if (voltageRange == 2) {
/*if (HQadcReadings[i]>>3 < 0b111111) adcReadings[i] = HQadcReadings[i]>>3 & 0b111111;
else adcReadings[i] = 0b111111;*/
adcReadings[i] = HQadcReadings[i]*ScaleConst*2;
} else if (voltageRange == 3) {
/*if (HQadcReadings[i]>>2 < 0b111111) adcReadings[i] = HQadcReadings[i]>>2 & 0b111111;
else adcReadings[i] = 0b111111;*/
adcReadings[i] = HQadcReadings[i]*ScaleConst*4;
}
if(adcReadings[i]>vScale){
adcReadings[i]=vScale;
}
// Invert for display
adcReadings[i] = vScale-adcReadings[i];
}
// Calculate and display frequency of signal using zero crossing
if (useThreshold != 0) {
if (useThreshold == 1) {
thresLocation = 1;
while ((adcReadings[thresLocation]<(vScale -(theThreshold>>2))) && (thresLocation<numOfSamples-1)) (thresLocation++);
thresLocation++;
while ((adcReadings[thresLocation]>(vScale -(theThreshold>>2))) && (thresLocation<numOfSamples-1)) (thresLocation++);
}
else if (useThreshold == 2) {
thresLocation = 1;
while ((adcReadings[thresLocation]>(vScale -(theThreshold>>2))) && (thresLocation<numOfSamples-1)) (thresLocation++);
thresLocation++;
while ((adcReadings[thresLocation]<(vScale -(theThreshold>>2))) && (thresLocation<numOfSamples-1)) (thresLocation++);
}
theFreq = (float) 1000/(thresLocation * (timePeriod+27)) * 1000;
}
// Average Voltage
avgV = 0;
for (i=0; i<numOfSamples; i++)
avgV = avgV + adcReadings[i];
avgV = (vScale -(avgV / numOfSamples)) * voltageConst;
// Maximum Voltage
maxV = vScale;
for (i=0; i<numOfSamples; i++)
if (adcReadings[i]<maxV) maxV = adcReadings[i];
maxV = (vScale-maxV) * voltageConst;
// Minimum Voltage
minV = 0;
for (i=0; i<numOfSamples; i++)
if (adcReadings[i]>minV) minV = adcReadings[i];
minV = (vScale-minV) * voltageConst;
// Peak-to-Peak Voltage
ptopV = maxV - minV;
}
void OscDisp(void){
int i,j;
DispClear();
if (useThreshold != 0)
for (i=0; i<127; i+=3){
DispSetPixel(i,vScale-(theThreshold>>2),1);
DispSetPixel(i,vScale,1);
}
j=LCDWidth/4;
for (i=0; i<vScale; i+=5) {
DispSetPixel(0,i,1);
DispSetPixel(j,i,1);
DispSetPixel(j+j,i,1);
DispSetPixel(j+j+j,i,1);
DispSetPixel(LCDWidth-1,i,1);
}
for (i=1; i<numOfSamples-1; i++){ // Draw using lines
drawLine(i-1,adcReadings[i-1],i,adcReadings[i], 1);
}
LCDisplay();
}
int main(void)
{
SystemInit();
interfaceINIT();
LCDInit(); // Инициализация дисплея
LCDisplay(); // Вывод картинки
Delay(2000);
LCD_clear(); // Очистка дисплея
LCD_set_XY(0,0); // Установка координат для вывода текста
LCD_write_string(" Core STM32F1 ");
LCD_write_string(" by DTViMS ");
LCD_write_string("Nokia 5110 LCD");
LCD_write_string(" Oscill 1.0 ");
LCD_write_string("Откомпилирован");
LCD_write_string(" Coocox IDE ");
Delay(2000);
ScaleConst=(float)(vScale+1)/(float)ADCScale;
voltageConst=3.3/(float)(vScale+1);
char buffer[16];
while(1)
{
collectData();
OscDisp();
LCD_set_XY(0,5);
sprintf(buffer,"%0.2f %0.2f %0.f",maxV,minV,theFreq);
LCD_write_string(buffer);
int tmp=(LCDWidth*timePeriod)/1000;
Delay((tmp<100?100-tmp:0)); // Медленный дисплей, шустрый процессор, надо бы РАВНОМЕРНО тормознуть процесс
}
}
void SysTick_Handler(void) // Счетчики милисекунд
{
if (TimingDelay != 0x00)
{
TimingDelay--;
}
if (UserTimingDelay != 0x00)
{
UserTimingDelay--;
}
}
На картинке слева дисплей подключенный к STM32, а справа дисплей цветной, подключенный к arduino, т.е. оригинальный проект данного осциллографа, подредактированный под конкретный монитор.
В варианте STM32 я уже подправил пару недостатков оригинальной программы, но убрал управление по USART. Жду сенсорный мониторчик, чтобы управление сделать на нем.