Если кто обратил внимание, предделители у таймеров Пики имеют тип float. То есть, вроде как можно подстраивать частоту плавно :) Давно меня занимала эта фича, только не на чем было проверить. А тут наконец приехал мне с Али логиканализатор на 100 МГц. Настроил PWM, макс значение счета 5 - соответственно частота должна получится 133 / 5 = 26.6 МГц. Установил предделитель 1.064, чтобы, значит, получить на выходе ровно 25 МГц
26.6 / 1.064 = 25 МГц
Чуда не произошло. Как я и предполагал, частота не настраивается плавно. 25 МГц из 26 делается примерно так - десяток импульсов на частоте 26.6 и один на частоте 20. Потом снова десяток на 26....
Ну так millis() в AVR так же работает. И 55-мс прерывания в DOS-сессии Windows - тоже.
25 МГц - это значит, 25000000 импульсов в секунду. Разве нет?
улыбнул значит )))
Да, есть проблема, объединил скетчи сканера wifi и двухтонального генератора и,
(выход синхронизации работает как и положено на 225 герц
а вот выход частоты 1800 пропускает импульсы, попробую перевести на другой пин...
делители float бывают только в сказках... из-за высокой частоты тактирования скорее всего на низких генерируемых частотах выходная частота будет весьма близка с требуемой...есть вероятность...
признавайтесь, кто SPI исследовал?
Не могу разобраться с установкой скорости в библиотеке Adafruit - не устанавливается.
SPI тянет от hardwarespi.h, там она по умолчанию 4 мегагерца, но при применении библиотеки Adafruit_ST7735 она явно сильно ниже
По осциллограмме ниже видно, что обмен идёт в 16 битном режиме на скорости 50 килогерц?
Откуда это берётся???
Для w5500 ставил 1 МГц, не работало, пришлось прицепить логанализатор, реально spi 1мгц было. Большую частоту не пробовал.
И при чем тут скорость передачи данных? Смотрим частоту clk пина spi, по нему и судим о скорости.
Ну, если я правильно вижу, в ячейке 5 мксек, два импульса в ячейке, аккурат 4мгц, не? Upd: не, Или 200 ns это ширина квадратика?
частота по символу H, что такое D пока не знаю (может время нарастания-спада сигнала), особо осциллограф не изучал, выставил исследование SPI и смотрю, обрабатывает не быстро иногда висит висит но так на экран ничего и не выведет, короче это не ригол )))
4 мегагерца это 250 наносекунд, 1 мегагерц - 1 микросекунда это у меня въелось )))
Работа с модемом SIM800L
Инициализация + чтение SMS в PDU формате, в том числе составных.
Пока только в 7и битной кодировке (латиница), кириллица позже будет.
#ifndef SIM800_PICO_H
#define SIM800_PICO_H
/// modem SIM800L UART
#define UART_ID uart0
#define BAUD_RATE 9600
#define DATA_BITS 8
#define STOP_BITS 1
#define PARITY UART_PARITY_NONE
// We are using pins 12 and 13, but see the GPIO function select table in the
// datasheet for information on which other pins can be used.
#define UART_TX_PIN 12
#define UART_RX_PIN 13
#define pinResetModem 23 // пин сброса модема
#define max_size_modem_rx_buf 2048 // приемный буфер данных от модема
#define period_wait_start_modem 15000UL // время ожидания модема после включения
#define period_wait_registration 120000UL // время ожидания регистрации модема в сети оператора
#define period_read_sms 10000UL // как часто с модема читать СМС
enum tModemGlobalStatus {modemStBegin = 0, modemStInit, modemStReg, modemStReboot, modemStReady};
void modemInit(void); // инициализируем пины
void modemReset(void); // сброс модема
void modemMainLoop(void);
union t_TP_MTIandCo {
struct {
unsigned TP_MTI:2;
unsigned TP_MMS:1;
unsigned res1:1;
unsigned res2:1;
unsigned TP_SRI:1;
unsigned TP_UDHI:1;
unsigned TP_RP:1;
};
unsigned char TP_MTI_Value;
};
#endif /* SIM800_PICO_H */
#include <stdio.h>
#include "pico/stdlib.h"
#include "sim800pico.h"
#include "millpico.h"
#include <string.h>
#include <ctype.h>
tModemGlobalStatus currentGlobalStatusModem = modemStBegin;
unsigned char modemRXbuf[max_size_modem_rx_buf];
unsigned short modemPosBuf;
unsigned char modemStepWork;
unsigned long modemTimerWork = 0UL;
unsigned char operatorName[16];
unsigned char operatorCSQ;
signed short findPosSubstringFromBuf(unsigned char * inStr) {
char * pStr = strstr((const char *) modemRXbuf, (const char *) inStr);
if (pStr) return (inStr - ((unsigned char*)pStr));
else return -1;
}
bool findOKRNfromBuf(void) {
if (findPosSubstringFromBuf((unsigned char *)"OK\r\n") >= 0) return true;
else return false;
}
void initModemUART(void) { // sim800 uart init
// Set up our UART with the required speed.
uart_init(UART_ID, BAUD_RATE);
// Set the TX and RX pins by using the function select on the GPIO
// Set datasheet for more information on function select
gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);
// Use some the various UART functions to send out data
// In a default system, printf will also output via the default UART
// Send out a character without any conversions
//uart_putc_raw(UART_ID, 'A');
// Send out a character but do CR/LF conversions
//uart_putc(UART_ID, 'B');
// Send out a string, with CR/LF conversions
//uart_puts(UART_ID, " Hello, UART!\n");
// Actually, we want a different speed
// The call will return the actual baud rate selected, which will be as close as
// possible to that requested
int __unused actual = uart_set_baudrate(UART_ID, BAUD_RATE);
// Set UART flow control CTS/RTS, we don't want these, so turn them off
uart_set_hw_flow(UART_ID, true, true);
// Set our data format
uart_set_format(UART_ID, DATA_BITS, STOP_BITS, PARITY);
// Turn off FIFO's - we want to do this character by character
uart_set_fifo_enabled(UART_ID, true);
}
void modemInit(void) { // инициализируем пины и все остальное
gpio_init(pinResetModem); // sim800 reset
gpio_set_dir(pinResetModem, GPIO_IN); // sim800 reset
gpio_put(pinResetModem, 0); // sim800 reset
initModemUART(); // sim800 uart init
}
void modemReset(void) { // сброс модема
gpio_set_dir(pinResetModem, GPIO_OUT);
sleep_ms(115);
gpio_set_dir(pinResetModem, GPIO_IN);
}
void modemClearRXbuf(void) {
modemPosBuf = 0;
memset(modemRXbuf, '\0', max_size_modem_rx_buf);
//modemRXbuf[modemPosBuf] = '\0';
}
void modemSendCMDandShowAndTimerStep(unsigned char * inStr) {
uart_puts(UART_ID, (const char*)inStr);
printf("%s\n", inStr);
modemTimerWork = millis(); // сбросим таймер
++modemStepWork; // На след шаг
}
bool processCREG(void) { // парсинг ответа модема на команду AT+CREG
char * p1 = strstr((const char *) modemRXbuf, (const char *) "+CREG: ");
if (p1) {
if (p1 >= ((const char *) modemRXbuf)) {
char * p2 = strchr((const char *) modemRXbuf, ',');
if (p2) {
if (p2 > p1) {
unsigned char br = *(p2+1);
if ((br == '1') || (br == '5')) return true;
}
}
}
}
return false;
}
void processCOPS(void) { // парсинг ответа модема на команду AT+COPS
char * p1 = strstr((const char *) modemRXbuf, (const char *) "+COPS: ");
if (p1) {
if (p1 >= ((const char *) modemRXbuf)) {
char * p2 = strchr((const char *) modemRXbuf, ',');
if (p2) {
char * p3 = strchr((p2+1), ',');
if (p3) {
if ((p3>p2) && ((*(p3+1)) == '"')) {
char * p4 = strchr((p3+2), '"');
if ((p4) && (p4>(p3+2))) {
unsigned char lenP = p4-p3-2;
for (unsigned char i=0; i<lenP; ++i) operatorName[i] = *(p3+2+i);
operatorName[lenP] = '\0';
}
}
}
}
}
}
}
void processCSQ(void) { // парсинг ответа модема на команду AT+CSQ
char * p1 = strstr((const char *) modemRXbuf, (const char *) "+CSQ: ");
if (p1) {
if (p1 >= ((const char *) modemRXbuf)) {
if (isdigit(*(p1+6))) {
unsigned char tC = (*(p1+6)) - '0';
if (isdigit(*(p1+7))) {
operatorCSQ = tC*10+((*(p1+7)) - '0');
} else {
operatorCSQ = tC;
}
}
}
}
}
bool modemCMDstReg(bool inLine) {
static unsigned long timerRegistration;
static bool goodCREG;
switch (modemStepWork) {
case 0: {
timerRegistration = millis();
goodCREG = false;
++modemStepWork;
break;
}
case 1: {
modemSendCMDandShowAndTimerStep((unsigned char *)"AT+CREG?\r"); // проверяем зарегестрировался ли модем в сети
break;
}
case 2: {
if ((millis() - timerRegistration) >= period_wait_registration) return false;
if ((millis() - modemTimerWork) >= 5000UL) { // больше 5 сек нет ответа
modemTimerWork = millis(); // сбросим таймер
modemStepWork = 25; // перейдем на паузу 5 секунд, что бы потом опять запросить статус регистрации
} else {
if (inLine) { // если пришла строка
if (processCREG()) goodCREG = true; // парсим строку - если зарегестрировались - ставим флаг
if (findOKRNfromBuf()) { // ищем ответ ОК
if (goodCREG) { // если успешно зарегестрировались
modemSendCMDandShowAndTimerStep((unsigned char *)"AT+COPS?\r"); // получить режим подключения к оператору и имя оператора
operatorName[0] = 0; // очищаем имя оператора
} else { // если так и не смогли зарегестрироваться
modemTimerWork = millis(); // сбросим таймер
modemStepWork = 25; // перейдем на паузу 5 секунд, что бы потом опять запросить статус регистрации
}
}
}
}
break;
}
case 3: {
if ((millis() - modemTimerWork) >= 5000UL) return false;
if (inLine) { // если пришла строка
processCOPS();
if (findOKRNfromBuf()) {
modemSendCMDandShowAndTimerStep((unsigned char *)"AT+CSQ\r"); // запрос качества связи
operatorCSQ = 0;
}
}
break;
}
case 4: {
if ((millis() - modemTimerWork) >= 5000UL) return false;
if (inLine) { // если пришла строка
processCSQ();
if (findOKRNfromBuf()) modemSendCMDandShowAndTimerStep((unsigned char *)"AT+CMGF=0\r"); // SMS в PDU формате
}
break;
}
case 5: {
if ((millis() - modemTimerWork) >= 5000UL) return false;
if (inLine && findOKRNfromBuf()) { // успешно закончили начальную инициализацию модема
currentGlobalStatusModem = modemStReady;
modemStepWork = 0;
}
break;
}
case 25: {
if ((millis() - modemTimerWork) >= 5000UL) modemStepWork = 1; // прождали и опять вернулись на запрос регистрации
break;
}
default: {}
}
return true;
}
bool modemCMDstInit(bool inLine) {
switch (modemStepWork) {
case 0: { // ждем пока модем прочухается
if ((millis() - modemTimerWork) >= period_wait_start_modem) ++modemStepWork; // На след шаг
break;
}
case 1: {
modemSendCMDandShowAndTimerStep((unsigned char *)"ATZ\r"); // проверка связи с модемом AT / сброс настроек на default - ATZ
break;
}
case 2: {
if ((millis() - modemTimerWork) >= 5000UL) return false;
if (inLine && findOKRNfromBuf()) modemSendCMDandShowAndTimerStep((unsigned char *)"ATE0\r"); // отключение(ATE0) ЭХО, т е модем в обратку не дублирует
break;
}
case 3: {
if ((millis() - modemTimerWork) >= 5000UL) return false;
if (inLine && findOKRNfromBuf()) modemSendCMDandShowAndTimerStep((unsigned char *)"ATV1\r"); // развернуты подробный ответ от модема
break;
}
case 4: {
if ((millis() - modemTimerWork) >= 5000UL) return false;
if (inLine && findOKRNfromBuf()) modemSendCMDandShowAndTimerStep((unsigned char *)"AT+CMEE=2\r"); // вывод подробных описаний ошибок
break;
}
case 5: {
if ((millis() - modemTimerWork) >= 5000UL) return false;
if (inLine && findOKRNfromBuf()) modemSendCMDandShowAndTimerStep((unsigned char *)"AT+CLIP=0\r"); // отключение АОН
break;
}
case 6: {
if ((millis() - modemTimerWork) >= 5000UL) return false;
if (inLine && findOKRNfromBuf()) modemSendCMDandShowAndTimerStep((unsigned char *)"ATS0=0\r"); // модем не берет трубку при входящем звонке
break;
}
case 7: {
if ((millis() - modemTimerWork) >= 5000UL) return false;
if (inLine && findOKRNfromBuf()) modemSendCMDandShowAndTimerStep((unsigned char *)"AT+CSCLK=0\r"); // отключение работы энергосберегающего режима через пин DTR
break;
}
case 8: {
if ((millis() - modemTimerWork) >= 5000UL) return false;
if (inLine && findOKRNfromBuf()) { // закончилась начальная инициализация
modemStepWork = 0;
currentGlobalStatusModem = modemStReg; // переходим в режим регистрации оператора
}
break;
}
default: {}
}
return true;
}
enum tSMSmode {smsStNone = 0, smsStGetList, smsStProcessing};
unsigned char smsGetByteFromTwoChars(char * inChars) {
unsigned char c1 = *inChars;
unsigned char outByte;
if (isdigit(c1)) outByte = c1 - '0'; else outByte = c1 - 55;
outByte *= 16;
c1 = *(inChars + 1);
if (isdigit(c1)) outByte += c1 - '0'; else outByte += c1 - 55;
return outByte;
}
unsigned char smsTextMsg7bit(char * begStr, char * endStr, char * outBuf, unsigned char msgLen) {
unsigned char outCharPos = 0; // позиция в выходном массиве
char * currCharPos = begStr; // указатель на символ откуда берем байт
unsigned char prevDataByte = 0; // предыдущий входящий байт
while ((currCharPos < endStr) && (outCharPos < msgLen)) {
unsigned char inDataByte = smsGetByteFromTwoChars(currCharPos); // входной байт
currCharPos += 2; // сразу сдвинем указатель на два символа вправо = 1 байт данных
unsigned char idxCurrByte = outCharPos % 8; // индекс сдвига входящего байта 0...7
if (idxCurrByte) {
unsigned char lowBits = prevDataByte >> (8 - idxCurrByte);
*(outBuf+outCharPos) = ((inDataByte << idxCurrByte) & 0x7F) | lowBits;
++outCharPos;
if (idxCurrByte == 7) {
*(outBuf+outCharPos) = inDataByte;
++outCharPos;
}
} else {
*(outBuf+outCharPos) = inDataByte & 0x7F;
++outCharPos;
}
prevDataByte = inDataByte; // сохраним для след байта данных
}
return outCharPos;
}
unsigned char smsTextMsg7bitWithOffset(char * begStr, char * endStr, char * outBuf, unsigned char msgLen, unsigned short inOffset) {
char * currCharPos = begStr; // указатель на символ откуда берем байт
unsigned char changeOutOffset = 0; // байт сдвига выходного буфера
if (inOffset) { // если первый байт сдвигается
*(outBuf) = smsGetByteFromTwoChars(currCharPos) >> inOffset; // кладем в выходной буфер со сдвигом
currCharPos += 2; // сразу сдвинем указатель на два символа вправо = 1 байт данных
changeOutOffset = 1; // будем на 1 символ больше класть в выходной буфер
}
unsigned char outCharPos = 0; // позиция в выходном массиве
unsigned char prevDataByte = 0; // предыдущий входящий байт
unsigned char idxCurrByte = 0; // индекс сдвига входящего байта 0...6
while ((currCharPos < endStr) && ((outCharPos+changeOutOffset) < msgLen)) {
unsigned char inDataByte = smsGetByteFromTwoChars(currCharPos); // входной байт
currCharPos += 2; // сразу сдвинем указатель на два символа вправо = 1 байт данных
if (idxCurrByte) {
unsigned char lowBits = prevDataByte >> (8 - idxCurrByte);
*(outBuf+outCharPos+changeOutOffset) = ((inDataByte << idxCurrByte) & 0x7F) | lowBits;
++outCharPos;
if (idxCurrByte == 6) {
*(outBuf+outCharPos+changeOutOffset) = inDataByte >> 1;
++outCharPos;
}
} else {
*(outBuf+outCharPos+changeOutOffset) = inDataByte & 0x7F;
++outCharPos;
}
prevDataByte = inDataByte; // сохраним для след байта данных
++idxCurrByte;
if (idxCurrByte >= 7) idxCurrByte = 0; // индекс по входящим байтам 0...6
}
return outCharPos+changeOutOffset;
}
// http://hardisoft.ru/soft/samodelkin-soft/poluchenie-i-dekodirovanie-sms-soobshhenij-v-formate-pdu/
void modemSMSprocessingLineText(void) {
static unsigned char smsDataIndex; // индекс смс
static unsigned char smsDataLenField; // длина данных из заголовка
char * p1 = strstr((const char *) modemRXbuf, (const char *) "+CMGL: ");
if ((p1) && (p1 >= ((const char *) modemRXbuf))) {
// вытаскиваем индекс СМСки
if (isdigit(*(p1+7))) {
smsDataIndex = (*(p1+7)) - '0';
if (isdigit(*(p1+8))) {
smsDataIndex = smsDataIndex * 10 +(*(p1+8)) - '0';
}
printf("smsDataIndex %d\r\n", smsDataIndex);
// вытаскиваем длину поля данных
p1 = strchr((const char *) (p1 + 7), ',');
if (p1) {
char * p2 = strchr((const char *) (p1 + 1), ',');
if (p2) {
p1 = strchr((const char *) (p2 + 1), ',');
if ((p1) && (p1>p2) && (isdigit(*(p1+1))) && (isdigit(*(p1+2)))) {
smsDataLenField = ((*(p1+1)) - '0') * 10 + ((*(p1+2)) - '0');
if (isdigit(*(p1+3))) {
smsDataLenField *= 10;
smsDataLenField += (*(p1+3)) - '0';
}
printf("smsDataLenField %d\r\n", smsDataLenField);
return; // строка успешно разпозналась - выходим
}
}
}
}
} else if ((smsDataIndex) && (smsDataLenField)) { // след строка уже будет опираться на предыдущие обработанные данные
char * smsPcurrentCharPos = (char*) modemRXbuf; // начало строки с данными
char * smsPendPosLine = strchr(smsPcurrentCharPos, '\r'); // последний символ строки с данными + 1
unsigned short smsDataCharsLenLine = smsPendPosLine - smsPcurrentCharPos; // общая длина строки с данными
if ((smsDataCharsLenLine % 2) == 0) { // количество символов должно быть четным
if ((smsDataCharsLenLine / 2) >= smsDataLenField) { // есть ли заголовок TP-SCA (номер СМС центра)
smsPcurrentCharPos += ((smsDataCharsLenLine/2) - smsDataLenField) * 2; // сдвигаем указатель строки начала данных вправо на длину TP-SCA
t_TP_MTIandCo TP_MTIandCo;
TP_MTIandCo.TP_MTI_Value = smsGetByteFromTwoChars(smsPcurrentCharPos);
printf("TP-MTI %d\r\n", TP_MTIandCo.TP_MTI);
printf("TP-MMS %d\r\n", TP_MTIandCo.TP_MMS);
printf("TP-SRI %d\r\n", TP_MTIandCo.TP_SRI);
printf("TP-UDHI %d\r\n", TP_MTIandCo.TP_UDHI);
printf("TP-RP %d\r\n", TP_MTIandCo.TP_RP);
smsPcurrentCharPos += 2; // указатель сдвигаем на два символа вправо = 1 байт
// адрес отправителя TP-OA
unsigned char lenTP_OA = smsGetByteFromTwoChars(smsPcurrentCharPos); // длина строки отправителя
smsPcurrentCharPos += 2; // указатель сдвигаем на два символа вправо = 1 байт
unsigned char typeTP_OA = smsGetByteFromTwoChars(smsPcurrentCharPos); // формат строки отправителя
smsPcurrentCharPos += 2; // указатель сдвигаем на два символа вправо = 1 байт
unsigned char smsSender[16]; // отправитель
switch (typeTP_OA) {
case 0x91: { // международный формат номера
unsigned char senderPos = 0;
while (senderPos < lenTP_OA) {
unsigned char ch1 = * (smsPcurrentCharPos + 1); // первый символ / перевернутая позиция
if (senderPos < lenTP_OA) {
smsSender[senderPos] = ch1; ++senderPos;
}
ch1 = * smsPcurrentCharPos; // второй символ // перевернутая позиция
if (senderPos < lenTP_OA) {
smsSender[senderPos] = ch1; ++senderPos;
}
smsPcurrentCharPos +=2; // указатель сдвигаем на два символа вправо = 1 байт
}
smsSender[senderPos] = '\0'; // конец строки
break;
}
default: { // тут остальные форматы номера,которые еще не запрограммированы, например текстовый отправитель, тупо сдвигаем позицию на нужгное кол.байт
unsigned char senderPos = 0;
while (senderPos < lenTP_OA) {
if (senderPos < lenTP_OA) {
smsSender[senderPos] = * smsPcurrentCharPos; ++senderPos;
}
if (senderPos < lenTP_OA) {
smsSender[senderPos] = * (smsPcurrentCharPos + 1); ++senderPos;
}
smsPcurrentCharPos +=2; // указатель сдвигаем на два символа вправо = 1 байт
}
smsSender[senderPos] = '\0'; // конец строки
}
}
printf("Sender %s\r\n", smsSender);
// TP-PID (Protocol identifier) – Идентификатор протокола. // не используем - пропускаем
smsPcurrentCharPos +=2; // указатель сдвигаем на два символа вправо = 1 байт
// TP-DCS (Data coding scheme) – Схема кодирования данных.
// 00 — 7-битная сжатая кодировка, 08 — UCS2, 10 и 18 — то же, только сообщение класса 0, т.е. Flash.
unsigned char TP_DCS = smsGetByteFromTwoChars(smsPcurrentCharPos);
printf("TP-DCS %02x\r\n", TP_DCS);
smsPcurrentCharPos +=2; // указатель сдвигаем на два символа вправо = 1 байт
// TP-SCTS (The service centre time stamp) – Штамп времени сервисного центра. Не используем.
smsPcurrentCharPos +=14; // указатель сдвигаем на 7 байт
// TP-UDL (User Data Length) — длина пользовательских данных, включая User Data header, если он есть. Если SMS закодирована 7-битной кодировкой, то данное поле указывает количество символов в сообщении. Если кодировка UCS2 – то поле указывает количество байт в сообщении.
unsigned char TP_UDL = smsGetByteFromTwoChars(smsPcurrentCharPos);
printf("TP-UDL %d\r\n", TP_UDL);
smsPcurrentCharPos +=2; // указатель сдвигаем на два символа вправо = 1 байт
// TP-UD (User Data) – Поле пользовательских данных. Здесь находится сам текст сообщения. В случае, если SMS длинная, т.е. разбита на несколько сообщений, данное поле начинается с заголовка TP-UDH. На наличие этого заголовка указывает бит TP-UDHI поля TP-MTI & Co.
unsigned char smsMessage[161]; // текст одного сообщения, по стандарту максимум 160 байт + терминатор
smsMessage[0] = '\0';
if (TP_MTIandCo.TP_UDHI == 0) { // сообщение из одного блока
if ((TP_DCS == 0x00) || (TP_DCS == 0x10)) { // 7и битная кодировка
smsMessage[smsTextMsg7bit(smsPcurrentCharPos, smsPendPosLine, (char *) smsMessage, TP_UDL)] = '\0';
} else if ((TP_DCS == 0x08) || (TP_DCS == 0x18)) { // кодировка UCS2
}
} else { // многоблочное сообщение
unsigned char UDHL = smsGetByteFromTwoChars(smsPcurrentCharPos);
printf("UDHL %02x\r\n", UDHL);
smsPcurrentCharPos +=2; // указатель сдвигаем на два символа вправо = 1 байт
// UDH
// IEI Для отправки длинных сообщений всегда равен либо 0х00, либо 0х08. Если 0х00 – то IED1 занимает 1 байт, если 0х08 – то IED1 занимает 2 байта.
unsigned char IEI = smsGetByteFromTwoChars(smsPcurrentCharPos);
printf("IEI %02x\r\n", IEI);
smsPcurrentCharPos +=2; // указатель сдвигаем на два символа вправо = 1 байт
// IEDL Длина данных информационного элемента – 3 или 4 байта, в зависимости от длины поля IED1
unsigned char IEDL = smsGetByteFromTwoChars(smsPcurrentCharPos);
printf("IEDL %02x\r\n", IEDL);
smsPcurrentCharPos +=2; // указатель сдвигаем на два символа вправо = 1 байт
// IED1 Номер-ссылка. Должен быть одинаков для всех частей сообщения
unsigned short IED1;
if (IEI == 0x00) {
IED1 = smsGetByteFromTwoChars(smsPcurrentCharPos);
smsPcurrentCharPos +=2; // указатель сдвигаем на два символа вправо = 1 байт
} else {
IED1 = smsGetByteFromTwoChars(smsPcurrentCharPos) * 256;
smsPcurrentCharPos +=2; // указатель сдвигаем на два символа вправо = 1 байт
IED1 += smsGetByteFromTwoChars(smsPcurrentCharPos);
smsPcurrentCharPos +=2; // указатель сдвигаем на два символа вправо = 1 байт
}
printf("IED1 %02x\r\n", IED1);
// IED2 Количество частей в сообщении
unsigned char IED2 = smsGetByteFromTwoChars(smsPcurrentCharPos);
printf("IED2 %02x\r\n", IED2);
smsPcurrentCharPos +=2; // указатель сдвигаем на два символа вправо = 1 байт
// IED3 Порядковый номер части сообщения
unsigned char IED3 = smsGetByteFromTwoChars(smsPcurrentCharPos);
printf("IED3 %02x\r\n", IED3);
smsPcurrentCharPos +=2; // указатель сдвигаем на два символа вправо = 1 байт
if ((TP_DCS == 0x00) || (TP_DCS == 0x10)) { // 7и битная кодировка
// считаем смещение септета
static unsigned short offset7bitFirstChar = 0;
unsigned short lenBytesWithUDH = TP_UDL*7/8; // длина поля UD с заголовком UDH
unsigned short lenBitsWOUDH = (lenBytesWithUDH - UDHL - 1) * 8; // длина поля с сообщением в битах уже без заголовка
unsigned short count7bitChars = lenBitsWOUDH / 7; // количество целиковых 7и битных символов
if ((IED3 == 1) && (IED2 > 1)) { // считаем для первой части сообщения, для остальных частей он аналогичный
offset7bitFirstChar = lenBitsWOUDH - (count7bitChars * 7); // filler 0-6 бит Наполнитель, который выравнивает text по границе септета
}
smsMessage[smsTextMsg7bitWithOffset(smsPcurrentCharPos, smsPendPosLine, (char *) smsMessage, count7bitChars, offset7bitFirstChar)] = '\0';
} else if ((TP_DCS == 0x08) || (TP_DCS == 0x18)) { // кодировка UCS2
}
}
printf("%s\r\n", smsMessage);
}
}
}
smsDataIndex = 0; // если не распозналась и не обработалась СМСка // или успешно обработалось - обнуляем все что сделали
}
void modemCMDworkSMS(bool inLine) {
static bool firstReadAllSMS = true;
static unsigned long smsReqListTimer = 0;
static unsigned long smsTimerWork;
static tSMSmode smsCurrentMode = smsStNone;
switch (smsCurrentMode) {
case smsStGetList: {
if (firstReadAllSMS) {
uart_puts(UART_ID, (const char*)"AT+CMGL=4,0\r");
printf("%s\n", "AT+CMGL=4,0\r\n");
firstReadAllSMS = false;
} else {
return;
uart_puts(UART_ID, (const char*)"AT+CMGL=0,0\r");
printf("%s\n", "AT+CMGL=0,0\r\n");
}
smsTimerWork = millis();
smsCurrentMode = smsStProcessing;
break;
}
case smsStProcessing: {
if ((millis() - smsTimerWork) >= 20000UL) {
smsReqListTimer = millis();
smsCurrentMode = smsStNone;
} else if (inLine) {
if (findOKRNfromBuf()) {
smsReqListTimer = millis();
smsCurrentMode = smsStNone;
} else {
modemSMSprocessingLineText();
}
}
break;
}
default: { // smsStNone
if ((millis() - smsReqListTimer) >= period_read_sms) smsCurrentMode = smsStGetList;
}
}
}
void modemMainLoop(void) {
switch (currentGlobalStatusModem) {
case modemStBegin: {
modemClearRXbuf();
modemStepWork = 0;
modemTimerWork = millis();
currentGlobalStatusModem = modemStInit;
break;
}
case modemStReboot: {
modemReset();
currentGlobalStatusModem = modemStBegin;
break;
}
default: { // main work by modem
unsigned char br = 0; // переменная куда падает входящий байт из модема
bool flLine = false; // влаг что пришла целиковая строка
while (uart_is_readable(UART_ID)) { // если что то пришло из модема
br = uart_getc(UART_ID); // читаем пришедший байт
if (br) { // если он больше нуля
modemRXbuf[modemPosBuf] = br; // кладем байт в буфер
++modemPosBuf; // сдвигаем указатель на следующую позицию
if (modemPosBuf >= max_size_modem_rx_buf) {
modemPosBuf = 0; // начнем с начала буфера при переполнении
flLine = true; // флаг что конец строки
break; // выходим из цикла
}
if ((br == '\r') || (br == '\n') || ((br >= ' ') && (br < 0x7F))) { // если символ печатный или конец строки
printf("%c", br); // выводим как есть
} else { // если не печатный
printf("x%02x", br); // выводим его шестнадцатиричное представление в лог
}
if (((br == '\n') && (modemPosBuf > 1) && (modemRXbuf[modemPosBuf-2] == '\r')) ||
((br == '\r') && (modemPosBuf > 1) && (modemRXbuf[modemPosBuf-2] == '\n'))) { // пришел конец строки
flLine = true; // флаг что конец строки
modemRXbuf[modemPosBuf] = '\0'; // прописываем терминатор/окончание строки
break; // выходим из цикла
}
}
}
// начинаем запуск всех обработчиков данных
switch (currentGlobalStatusModem) {
case modemStInit: {
if (!modemCMDstInit(flLine)) currentGlobalStatusModem = modemStReboot;
break;
}
case modemStReg: {
if (!modemCMDstReg(flLine)) currentGlobalStatusModem = modemStReboot;
break;
}
case modemStReady: {
modemCMDworkSMS(flLine);
break;
}
default: {}
}
// остальные обработчики
// если обработали целиковую строку
if (flLine) modemClearRXbuf(); // обнуляем массив
// end main work
}
}
tight_loop_contents();
}
cmsis это стандарт arm, он есть везде и он отвратительный.
почему это ? если более менее знаком с даташитом устройства для которого пишешь , то cmsis вполне себе понятен интуитивно .или вы другое имеете ввиду ?
Привет, подскажите что я делаю не так компилирую программу в main.uf2, перезагружаю с зажатым boot, закидываю на появившийся диск программу, она запускается и работает, но если перезагрузить плату программа больше не запускается. Только если опять закидывать через boot.
Нет, это неправильно, так быть не должно.
Где то в инете лежит что то типа clean.uf2, программа, которая чистить флэш и прочее в МК. Попробуйте его. Или другую прогу скомпилировать, понять так же себя МК ведёт или нет.
Нет, это неправильно, так быть не должно. Где то в инете лежит что то типа clean.uf2, программа, которая чистить флэш и прочее в МК. Попробуйте его. Или другую прогу скомпилировать, понять так же себя МК ведёт или нет.
Так не будет работать, т.к. используются не один бит (с помощью побитовых операций сдвига и логического сложения формируется управляющее слово из 24 бит).
Возьмите плату и светодиод и попробуйте. У меня она есть со встроенным светодиодом, код примера протестирован , ошибки исправлены.
В ошибке даже стрелочка нарисована, откуда берет.
хм,
оно?
ок, спасибо, пошел искать путь к этим переменным....
Интересный модуль...и по цене и по возможностям...
Самое приятное, с моей точки зрения:простота работы с периферией по сравнению с stm32 cmsis. Sdk хорОш!
SPI работает с полтычка, это точно, по PWM библиотека тоже простая...реальная замена ардуино нано и по цене и по простоте использования
простота = она же беднота.... Режимов таймера с гулькин нос
Для каждой задачи нужен свой МК, нужны таймеры - берём stm32.
отож!!! STM32WB55VG c памятью побольше )))
Чтобы было информативно, закину определения для PWM
Если кто обратил внимание, предделители у таймеров Пики имеют тип float. То есть, вроде как можно подстраивать частоту плавно :) Давно меня занимала эта фича, только не на чем было проверить. А тут наконец приехал мне с Али логиканализатор на 100 МГц. Настроил PWM, макс значение счета 5 - соответственно частота должна получится 133 / 5 = 26.6 МГц. Установил предделитель 1.064, чтобы, значит, получить на выходе ровно 25 МГц
26.6 / 1.064 = 25 МГц
Чуда не произошло. Как я и предполагал, частота не настраивается плавно. 25 МГц из 26 делается примерно так - десяток импульсов на частоте 26.6 и один на частоте 20. Потом снова десяток на 26....
Может я что не так настроил - попробуйте сами.
Ну так millis() в AVR так же работает. И 55-мс прерывания в DOS-сессии Windows - тоже.
25 МГц - это значит, 25000000 импульсов в секунду. Разве нет?
Ну так millis() в AVR так же работает. И 55-мс прерывания в DOS-сессии Windows - тоже.
25 МГц - это значит, 25000000 импульсов в секунду. Разве нет?
улыбнул значит )))
Да, есть проблема, объединил скетчи сканера wifi и двухтонального генератора и,
(выход синхронизации работает как и положено на 225 герц
а вот выход частоты 1800 пропускает импульсы, попробую перевести на другой пин...
ничего не дало, на другом пине также пропускает
делители float бывают только в сказках... из-за высокой частоты тактирования скорее всего на низких генерируемых частотах выходная частота будет весьма близка с требуемой...есть вероятность...
делители float бывают только в сказках...
читаем даташит и описание SDK внимательно....
25 МГц - это значит, 25000000 импульсов в секунду. Разве нет?
это как посмотреть :)
Можно сказать и так - "частота 25 МГц это означает что импульсы идут через каждые 1/ 25 000 000 секунды".... и тут уже будут нюансы
делители float бывают только в сказках...
читаем даташит и описание SDK внимательно....
я жеж безграмотный, поговорить куда ни шло )))
Если оставить только два PWM то всё работает как надо и 1800 и 2250 ...
Ребята, если чё, так Вы работаете с цифровой техникой, не забыли?
Ребята, если чё, так Вы работаете с цифровой техникой, не забыли?
ясный пень аналоговнет
Ребята, если чё, так Вы работаете с цифровой техникой, не забыли?
а вдруг? :)
25 МГц - это значит, 25000000 импульсов в секунду. Разве нет?
это как посмотреть :)
Можно сказать и так - "частота 25 МГц это означает что импульсы идут через каждые 1/ 25 000 000 секунды".... и тут уже будут нюансы
И, кстати, Петрович выше справедливо заметил, что мы имеем дело с цифрой, а потому 25000000 импульсов в секунду и никаких дополнительных условий.
признавайтесь, кто SPI исследовал?
Не могу разобраться с установкой скорости в библиотеке Adafruit - не устанавливается.
SPI тянет от hardwarespi.h, там она по умолчанию 4 мегагерца, но при применении библиотеки Adafruit_ST7735 она явно сильно ниже
По осциллограмме ниже видно, что обмен идёт в 16 битном режиме на скорости 50 килогерц?
Откуда это берётся???
Для w5500 ставил 1 МГц, не работало, пришлось прицепить логанализатор, реально spi 1мгц было. Большую частоту не пробовал.
И при чем тут скорость передачи данных? Смотрим частоту clk пина spi, по нему и судим о скорости.
CLK на осциллограмме зелёный луч
Ну, если я правильно вижу, в ячейке 5 мксек, два импульса в ячейке, аккурат 4мгц, не?
Upd: не,
Или 200 ns это ширина квадратика?
частота по символу H, что такое D пока не знаю (может время нарастания-спада сигнала), особо осциллограф не изучал, выставил исследование SPI и смотрю, обрабатывает не быстро иногда висит висит но так на экран ничего и не выведет, короче это не ригол )))
4 мегагерца это 250 наносекунд, 1 мегагерц - 1 микросекунда это у меня въелось )))
Получается период (грубо) 2.5 мкс, значит частота 400 кГц, библиотека врет, используем sdk и прямое общение с устройством, и наступит счастье)
так не бывает, где-то однозначно должно это устанавливаться, пока не нашёл где...
Работа с модемом SIM800L
Инициализация + чтение SMS в PDU формате, в том числе составных.
Пока только в 7и битной кодировке (латиница), кириллица позже будет.
-
Update:
обновленный код - расшифровка в том числе русских СМС
а у нутрях ядра cmsis присутствует )))
PS а у MBED и CMSIS и HAL ...
cmsis это стандарт arm, он есть везде и он отвратительный.
cmsis это стандарт arm, он есть везде и он отвратительный.
...есть осталось только дерьмо мамонта... зато его много... (из анекдота)
cmsis это стандарт arm, он есть везде и он отвратительный.
[MBED
Мбед отстой... впрочем я им никогда не пользовался Ж)
cmsis это стандарт arm, он есть везде и он отвратительный.
не соглашусь, по факту это определение регистров/прерываний и прочего чипа.
не нравиться CMSIS - пишите напрямую в адреса, данные все есть в даташите.
А кто нибудь пробовал RP2040 подключать к LCD 1602 экрану? Нахожу пока только поврежденные библиотеки.
А кто нибудь пробовал RP2040 подключать к LCD 1602 экрану? Нахожу пока только поврежденные библиотеки.
А что, есть проблемы?
Да, есть проблема. Ни одна библиотека из zip формата не распаковывается, поскольку программа не может найти файл с расширением *.h
Да, есть проблема. Ни одна библиотека из zip формата не распаковывается, поскольку программа не может найти файл с расширением *.h
вот эта и распаковывается и компилируется, подключать дисплей влом (обязан работать)
Привет, подскажите что я делаю не так компилирую программу в main.uf2, перезагружаю с зажатым boot, закидываю на появившийся диск программу, она запускается и работает, но если перезагрузить плату программа больше не запускается. Только если опять закидывать через boot.
Нет, это неправильно, так быть не должно.
Где то в инете лежит что то типа clean.uf2, программа, которая чистить флэш и прочее в МК. Попробуйте его. Или другую прогу скомпилировать, понять так же себя МК ведёт или нет.
я в таком случае заливаю разные версии питона
Я компилирую через wsl (ubuntu ) по win10, если через arduino ide 2.0 то все ок.
а зачем так сложно?
rp2040 sdk под linux прекрасно разворачивается и работает без всяких лишних прокладок.
делители float бывают только в сказках...
с натяжкой в синтезаторах вроде si5351, там правда оно из несколько коэффициентов и отдельный PLL
В коде сообщения #292 ошибка, белый цвет так не получить.
Вместо логического сложения (дизъюнкции, операции «ИЛИ») хитрый кетаец вставил просто сложение "+". Зачем???
В коде сообщения #292 ошибка, белый цвет так не получить.
Вместо логического сложения (дизъюнкции, операции «ИЛИ») хитрый кетаец вставил просто сложение "+". Зачем???
к сожалению в посте код уже не поправить, надо выкладывать новую правленную функцию
В данном случае разницы между + и | нет !
0 +1 = 1
и
0 | 1 = 1
Второй операнд в данном примере всегда 0.
к сожалению в посте код уже не поправить, надо выкладывать новую правленную функцию
Кому надо разберутся.
В данном случае разницы между + и | нет !
0 +1 = 1
и
0 | 1 = 1
Второй операнд в данном примере всегда 0.
Так не будет работать, т.к. используются не один бит (с помощью побитовых операций сдвига и логического сложения формируется управляющее слово из 24 бит).
Возьмите плату и светодиод и попробуйте. У меня она есть со встроенным светодиодом, код примера протестирован , ошибки исправлены.
Вместо логического сложения (дизъюнкции, операции «ИЛИ») хитрый кетаец вставил просто сложение "+". Зачем???
Прежде чем обвинять китайца в хитрости, башкой подумай. Попытайся сложить
0110 0000 0000 +
0000 1100 0000 +
0000 0000 0011 = ?
Потом расскажешь, чо получилось