Привет, Geektimes! Вам было когда нибудь интересно, как «звучит» электрический сигнал, проходящий по дорожкам печатных плат между микросхем, транзисторов, диодов, резисторов и конденсаторов? Один из вариантов такого сигнала в современной электронике — цифровая шина, а один из популярных интерфейсов для обмена данных по шине — UART. Он часто используется в микроконтроллерах для связи с компьютером или какой либо переферией. Чтобы получить звук на шине, вовсе не обязательно подключать динамик с усилителем к реальной шине с UARTом, ведь ее можно симулировать в программе. Вам интересно, какие звуки в итоге получились, или нужна программа, чтобы самому поэкспериментировать? Тогда прошу под кат.
Слушаем файлы на шине с UART
Какой звук получится, если передавать файлы через UART? Вот некоторые примеры, полученные при следующих параметрах UART:
- Скорость 115200 бод
- Разрядность 8 бит
- Бит проверки на четность: отсутствует
- Длина стоп бита: 1
Звук игры Сталкер Тень Чернобыля (файл XR_3DA.exe, в самом конце трека, начиная с 2:36, есть мелодия).
Звук текста и кода статьи про синтезатор речи (сама статья тут).
Как звучит фотография «Лены»?
Получился просто шум.
Звук книги «Энтропия и прогноз времянных рядов в теории динамических систем» в pdf формате.
Звук прошивки микроконтроллера серии Atmega для wav плеера.
Для чего это можно использовать?
Теоретически, может быть такая информация в виде текста, или картинки, или видео, или в виде программы, которая будет иметь не только функциональный смысл или эстетическую значимость, но также и «красивый» звук цифровой шины, тогда это получается некая «цифровая» поэзия. Также можно разнообразить сэмплы для дабстепа Вообще, на мой взгляд, слушать звуки цифровой шины примерно так же интересно, как слушать шум радиоволн на коротких волнах, в общем на любителя.
Как это работает или немного про UART
Что такое UART можно почитать на википедии. UART очень легко симулировать в программе. По сути необходимо лишь уметь создавать перепад сигнала от 0 до 1 и обратно (в случае WAV файла с разрядностью 16 бит, это значения от —A до +A, где A это ампилутда сигнала) и записывать его в звуковой файл. Интерфейс UART функционирует примерно так: после стартового бита, который равен логическому «нулю», нужно выставлять уровень в зависимости от предоставленных данных, от младшего бита к старшему. Далее идет бит четности, который можно не использовать. Под конец сообщения ставится стоп бит (логическая «единица»), длина которого может быть разной. Пример кода можно посмотреть в исходниках, которые есть в конце статьи. Подробнее про UART можно посмотреть в сети, материала очень много. UART можно использовать не по назначению, например как ШИМ, а в нашем случае это означает, что теоретически можно даже передать полноценный звуковой сигнал сразу на динамик, как это делается в wav плеерах на микроконтроллере. Однако, я скорее предлагаю использовать его как генератор меандра. Частоту тона и фазу сигнала при этом можно предоставлять в виде бит данных, например 00001111 создаст меандр, период которого будет равен 10-ти периодам времени передачи одного бита (так как в данном случае есть еще стартовый бит, равный 0, и стоповый бит, равный 1). Из-за стартового и стопового бита не все периоды меандров получится передать, например в таком случае 01100110, так как по сути мы будем слушать такую последовательность на шине 0011001101. Если использовать высокую скорость передачи данных, например 115200 бод, то имеет смысл создавать слышимые звуковые частоты, растянув периоды меадров на несколько байт.
…
По данной ссылке можно скачать программу для преобразования файла в звук шины UART. Также есть версия с использованием OpenAL, чтобы воспроизводить звук в процессе работы программы, вот ссылка.
Исходный код программы предоставлен ниже:
#ifndef SOUNDS_DIGITAL_BUS_H_INCLUDED #define SOUNDS_DIGITAL_BUS_H_INCLUDED #define SDB_WAV_FILE_NAME "sdb_output.wav" #define SDB_UART_BIT 8 #define SDB_UART_PARITY 0 #define SDB_UART_STOP_BIT 1 #define SDB_UART_BAUDRATE 9600 #define SDB_UART_BAUDRATE_MAX 921600 /// максимальное значение (амплитуда) сэмпла аудио #define SDB_MAX_DATA 30000 /// каналов в аудио #define SDB_CANNEL 1 /// кол-во бит (разрешение) аудио #define SDB_BIT 16 /// частота дискретизации аудио #define SDB_FREQUENCY 96000 /// Количество буферов в очереди OpenAL #define OPENAL_NUM_OF_DYNBUF 32 /// Настройки OpenAL #define SDB_OPENAL_BIT SDB_BIT #define SDB_OPENAL_CANNEL SDB_CANNEL #define SDB_OPENAL_FREQUENCY SDB_FREQUENCY #define SDB_OPENAL_FORMAT AL_FORMAT_MONO16 /// Количество байт в буфере #define SDB_BUFFER_MAX 4800 /// использовать OpenAL для вывода аудио (если Да, то выставить 1) #define SDB_WITH_OPENAL 1 /// режим отладки (если Да, то выставить 1) #define SDB_WITH_DEBUG_MODE 0 #if SDB_WITH_OPENAL == 1 // Подключение библиотеки OpenAL Для вывода звука #include #include #endif #if SDB_WITH_DEBUG_MODE == 1 // Для режима отладки #include #include #endif //для работы с файлами #include //для работы со строками #include class sdb { private: #if SDB_WITH_OPENAL == 1 // работа с openAl взята из библиотеки // синтезатора речи speesy ALCdevice* openAlDevice; ALCcontext* openAlContext; ALuint openAlSource; signed char openAlnBuf; //количество буферов #endif // ---------------------------------------- // для записи в WAV файл FILE *fpSave; unsigned short wavBlockAlign; unsigned long wavSubchunk2Size; unsigned long wavChunkSize; unsigned char wavLenDataType; // ---------------------------------------- // для генерирования звуков шин данных double dTime; // длина времени одного сэмпла, в с. double allTime; // общее время трека short busState; // состояние шины (уровень сигнала) short busDataOne[SDB_BUFFER_MAX]; // буферы, куда пишем wav short busDataTwo[SDB_BUFFER_MAX]; unsigned char switchBuffer; // переключатель между буферами unsigned int posBufferOne, posBufferTwo; // позиция в буферах unsigned int posAllBuffer; // общая позиция char wavFileName[512]; // имя wav файла char isCreateWavFileFlag; // флаг, что wav файл был создан char isBufferOneFlag; // флаг, что готов первый буфер char isBufferTwoFlag; unsigned int uartBaudrate; // скорость UART в бод unsigned int uartT; unsigned char uartBit; // количество бит unsigned char uartStopBit; // количество стоп бит unsigned char uartParityBit; unsigned char isAudioOutput; unsigned char isWavFileOutput; #if SDB_WITH_OPENAL == 1 ALboolean CheckALCError(void); ALboolean CheckALError(void); char initOpenAL(void); void destroyOpenAL(void); void playOpenAlSound(void); void stopOpenAlSound(void); void closeOpenAlSound(void); int getBufferStatusOpenAl(void); void setBufferOpenAl(signed short *buf,unsigned long siz); char updateOpenAl(void); #endif char createWavFile(char * filename,unsigned long sampleRate,unsigned short bitsPerSample, unsigned short numChannels); void writeSampleWavFile(void *data); void writeDataBlockWavFile(void *data,unsigned long len); void closeWavFile(void); void busDelay(unsigned short us); public: sdb(void); ~sdb(void); /** @brief функция генерирует звук одного байта шины 1-wire @param[in] data байт для отправки по 1-wire */ void oneWireSendByte(unsigned char data); /** @brief генерирует звук сброса шины 1-wire */ void oneWireReset(void); /** @brief останаливает работу шины 1- wire */ void oneWireStop(void); /** @brief передает один байт по шине UART @param[in] data один символ шины UART */ void uartSendByte(unsigned char data); /** @brief передает данные по шине UART @param[in] data один символ шины UART */ void uartSend(unsigned long data); /** @brief устанавливает скорость UART @param[in] baudrate скорость шины UART */ void uartSetBaudrate(unsigned long baudrate); /** @brief устанавливает количество отправляемых бит @param[in] bit количество бит, отправляемых шиной UART за один раз */ void uartSetBit(unsigned char bit); /** @brief устанавливает количество стоп битов Данная функция устаналивает количество стоп битов. Минимальное значение стоп бита 1. @param[in] bit количество стоп битов */ void uartSetStopBit(unsigned char bit); /** @brief устанавливает бит четности Данная функция устанавливает флаг использования в UART бита четности. Если передать 1, то бит четности будет задействован, если передать 0, то передача данных по UART будет идти без бита четности. @param[in] state флаг, включающий бит четности. */ void uartSetParityBit(unsigned char state); /** @brief функция останавливает передачу UART Данная функция завершает работу UART, сохраняет или воспроизводит оставшиеся байты. Функцию вызывать обязательно в конце передачи данных по шине. */ void uartStop(void); /** @brief функция устанавливает имя wav файла @param[in] filename имя wav файла */ void setWavFileName(char* filename); /** @brief включить вывод аудио через OpenAL */ void playAudioOn(void); /** @brief выключить вывод аудио через OpenAL */ void playAudioOff(void); /** @brief включить запись аудио в wav файл */ void recordOn(void); /** @brief выключить запись аудио в wav файл */ void recordOff(void); }; #endif // MUSICDIGITALBUS_H_INCLUDED
#include "SoundsDigitalBus.h" #if SDB_WITH_OPENAL == 1 // обработчики ошибок ALboolean sdb::CheckALCError(void) { ALenum ErrCode; ErrCode = alcGetError(openAlDevice); if (ErrCode != ALC_NO_ERROR) { return AL_FALSE; } return AL_TRUE; } ALboolean sdb::CheckALError(void) { ALenum ErrCode; if ((ErrCode = alGetError()) != AL_NO_ERROR) { return AL_FALSE; } return AL_TRUE; } // инициализация OpenAL char sdb::initOpenAL(void) { ALfloat SourcePos[] = {0.0, 0.0, 0.0}; ALfloat SourceVel[] = {0.0, 0.0, 0.0}; // Позиция слушателя. ALfloat ListenerPos[] = { 0.0, 0.0, 0.0 }; // Скорость слушателя. ALfloat ListenerVel[] = { 0.0, 0.0, 0.0 }; // Ориентация слушателя. (Первые 3 элемента – направление «на», последние 3 – «вверх») ALfloat ListenerOri[] = { 0.0, 0.0, -1.0, 0.0, 1.0, 0.0 }; #if SDB_WITH_DEBUG_MODE == 1 printf("alcOpenDevicen"); #endif openAlDevice = alcOpenDevice(0); // open default device if (openAlDevice != 0) { openAlContext = alcCreateContext(openAlDevice,0); // create context if (openAlContext != 0) { #if SDB_WITH_DEBUG_MODE == 1 printf("alcMakeContextCurrentn"); #endif alcMakeContextCurrent(openAlContext); // set active context } else { #if SDB_WITH_DEBUG_MODE == 1 printf("Error contextn"); #endif return 0; } } else { #if SDB_WITH_DEBUG_MODE == 1 printf("Error Open Devicen"); #endif return 0; } // Позиция alListenerfv(AL_POSITION, ListenerPos); // Скорость alListenerfv(AL_VELOCITY, ListenerVel); // Ориентация alListenerfv(AL_ORIENTATION, ListenerOri); alGenSources(1, &openAlSource); if (!CheckALError()) return false; alSourcef (openAlSource, AL_PITCH, 1.0f); alSourcef (openAlSource, AL_GAIN, 1.0f); alSourcefv(openAlSource, AL_POSITION, SourcePos); alSourcefv(openAlSource, AL_VELOCITY, SourceVel); alSourcei (openAlSource, AL_LOOPING, AL_FALSE); alSourcei(openAlSource, AL_LOOPING, AL_FALSE); openAlnBuf = 0; return 1; } void sdb::destroyOpenAL(void) { alSourceStop(openAlSource); // Выключаем текущий контекст alcMakeContextCurrent(0); // Уничтожаем контекст alcDestroyContext(openAlContext); // Закрываем звуковое устройство alcCloseDevice(openAlDevice); } void sdb::playOpenAlSound(void) { alSourcePlay(openAlSource); } void sdb::stopOpenAlSound(void) { alSourceStop(openAlSource); } void sdb::closeOpenAlSound(void) { alSourceStop(openAlSource); if (alIsSource(openAlSource)) alDeleteSources(1, &openAlSource); } int sdb::getBufferStatusOpenAl(void) { int processed = 0; if (openAlnBuf == 0) return 1; alGetSourcei(openAlSource, AL_BUFFERS_PROCESSED, &processed); CheckALError(); #if SDB_WITH_DEBUG_MODE == 1 printf("getBufferStatus: %dn",processed); #endif if (processed != 0) { return processed; } return 0; } void sdb::setBufferOpenAl(signed short* buf, unsigned long siz) { int processed = 0; ALuint BufID = 0; #if _OPENAL_FORMAT == AL_FORMAT_MONO16 siz = siz*2; #endif // _OPENAL_FORMAT #if _OPENAL_FORMAT == AL_FORMAT_STEREO16 siz = siz*4; #endif // _OPENAL_FORMAT #if _OPENAL_FORMAT == AL_FORMAT_STEREO8 siz = siz*2; #endif // _OPENAL_FORMAT // Получаем количество отработанных буферов alGetSourcei(openAlSource, AL_BUFFERS_PROCESSED, &processed); CheckALError(); //если отработанных буферов нет, есть новые данные и число буферов не превысило максимума if ((processed == 0) && (openAlnBuf < OPENAL_NUM_OF_DYNBUF)) { openAlnBuf++; //увеличиваем число буферов alGenBuffers(1, &BufID); //создаем новый буфер alBufferData(BufID,SDB_OPENAL_FORMAT,buf,siz,SDB_OPENAL_FREQUENCY); //загружаем данные в новый буфер alSourceQueueBuffers(openAlSource, 1, &BufID); //добавляем буфер в очередь if (openAlnBuf == 1) alSourcePlay(openAlSource); } else { #if SDB_WITH_DEBUG_MODE == 1 printf("processed: %d openAlnBuf: %dn",processed,openAlnBuf); #endif // ждем, когда будет обработан хотя бы один буфер while (getBufferStatusOpenAl() == 0); // убираем из очереди буфер alSourceUnqueueBuffers(openAlSource, 1, &BufID); CheckALError(); // загружаем новый буфер alBufferData(BufID,SDB_OPENAL_FORMAT,buf,siz,SDB_OPENAL_FREQUENCY); CheckALError(); alSourceQueueBuffers(openAlSource, 1, &BufID); CheckALError(); } } // функция очищяет все буферы по мере их опустошения, и останавливает проигрывание // возвращает 1 если еще есть не пустые буферы char sdb::updateOpenAl(void) { int processed = 0; ALuint BufID; // Получаем количество отработанных буферов alGetSourcei(openAlSource, AL_BUFFERS_PROCESSED, &processed); #if SDB_WITH_DEBUG_MODE == 1 printf("updateOpenAl: %dn",processed); #endif // если обработаны все буферы if (openAlnBuf == processed) { // Если таковые существуют то while (processed--) { // Исключаем их из очереди alSourceUnqueueBuffers(openAlSource, 1, &BufID); if (!CheckALError()) return 0; alDeleteBuffers(1, &BufID); openAlnBuf--; } alSourceStop(openAlSource); #if SDB_WITH_DEBUG_MODE == 1 printf("alSourceStop: %dn",openAlnBuf); #endif return 0; } return 1; } #endif // задержка для шин данных. тут генерируется звук void sdb::busDelay(unsigned short us) { double Time = (double)us/1000000.0; double locTime = allTime; char isFlag = 0; // создаем wav файл, если он не был создан ранее if (isCreateWavFileFlag == 0) { if (isWavFileOutput == 1) { isFlag = createWavFile(wavFileName,SDB_FREQUENCY,SDB_BIT,SDB_CANNEL); // если файл был успешно открыт, то ставим флаг if (isFlag == 1) isCreateWavFileFlag = 1; } if (isAudioOutput == 1) { initOpenAL(); if (isWavFileOutput == 0) isCreateWavFileFlag = 1; } } allTime = allTime + Time; // если файл был открыт if (isCreateWavFileFlag == 1) // начинаем делать сэмплы аудиоданных while(locTime < allTime) { if (switchBuffer == 0) { if (posBufferOne >= SDB_BUFFER_MAX) { posBufferOne = 0; posBufferTwo = 0; busDataTwo[posBufferTwo++] = busState; isBufferOneFlag = 1; switchBuffer = 1; if (isWavFileOutput == 1) writeDataBlockWavFile(busDataOne,SDB_BUFFER_MAX); #if SDB_WITH_OPENAL == 1 if (isAudioOutput == 1) setBufferOpenAl(busDataOne,SDB_BUFFER_MAX); #endif } else { busDataOne[posBufferOne++] = busState; } } else if (switchBuffer == 1) { if (posBufferTwo >= SDB_BUFFER_MAX) { posBufferOne = 0; posBufferTwo = 0; busDataOne[posBufferOne++] = busState; isBufferTwoFlag = 1; switchBuffer = 0; if (isWavFileOutput == 1) writeDataBlockWavFile(busDataTwo,SDB_BUFFER_MAX); #if SDB_WITH_OPENAL == 1 if (isAudioOutput == 1) setBufferOpenAl(busDataTwo,SDB_BUFFER_MAX); #endif } else { busDataTwo[posBufferTwo++] = busState; } } posAllBuffer++; locTime = locTime + dTime; } } char sdb::createWavFile(char * filename,unsigned long sampleRate,unsigned short bitsPerSample, unsigned short numChannels) { char type[4]; const unsigned long subchunk1Size = 16; unsigned long byteRate; const unsigned short audioFormat = 1; unsigned short len_str = 0; char str_filename[512] = {0}; unsigned short i; // количество байт в одном сэмле одного канала wavLenDataType = bitsPerSample/8; wavSubchunk2Size = 0; wavChunkSize = wavSubchunk2Size + 44 - 8; // Количество байт на одну выборку wavBlockAlign = bitsPerSample / (8 * numChannels); //Количество байт, переданных за секунду воспроизведения. byteRate = sampleRate * wavBlockAlign; strcpy(str_filename,filename); len_str = strlen(str_filename); if (len_str < 4) return 0; // проверка имени файла на наличие расширения .wav i = 0; while(i < len_str) { if (filename[i] == '.' && (i + 3) < len_str) { if (((filename[i + 1] == 'w') && (filename[i + 2] == 'a') && (filename[i + 3] == 'v')) || ((filename[i + 1] == 'W') && (filename[i + 2] == 'A') && (filename[i + 3] == 'V'))) { // если имя имеет расширение wav break; } else { if ((i + 3) >= 512) return 0; filename[i + 1] = 'w'; filename[i + 2] = 'a'; filename[i + 3] = 'v'; len_str = i + 4; break; } } else if ((i + 1) == len_str) { if ((i + 3) >= 512) return 0; filename[i + 1] = '.'; filename[i + 2] = 'w'; filename[i + 3] = 'a'; filename[i + 4] = 'v'; len_str = i + 5; break; } i++; } type[0] = filename[len_str - 4]; type[1] = filename[len_str - 3]; type[2] = filename[len_str - 2]; type[3] = filename[len_str - 1]; if (type[0]!='.'||type[1]!='w'||type[2]!='a'||type[3]!='v') { if (type[0]!='.'||type[1]!='W'||type[2]!='A'||type[3]!='V') { return 0; } } fpSave=fopen(str_filename,"wb"); type[0]='R'; type[1]='I'; type[2]='F'; type[3]='F'; fwrite(&type,sizeof(char),4,fpSave); fwrite(&wavChunkSize,sizeof(unsigned long),1,fpSave); type[0]='W'; type[1]='A'; type[2]='V'; type[3]='E'; fwrite(&type,sizeof(char),4,fpSave); type[0]='f'; type[1]='m'; type[2]='t'; type[3]=' '; fwrite(&type,sizeof(char),4,fpSave); fwrite(&subchunk1Size,sizeof(unsigned long),1,fpSave); fwrite(&audioFormat,sizeof(unsigned short),1,fpSave); fwrite(&numChannels,sizeof(unsigned short),1,fpSave); fwrite(&sampleRate,sizeof(unsigned long),1,fpSave); fwrite(&byteRate,sizeof(unsigned long),1,fpSave); fwrite(&wavBlockAlign,sizeof(unsigned short),1,fpSave); // Количество бит в сэмпле. Так называемая “глубина” или точность звучания. 8 бит, 16 бит и т.д. fwrite(&bitsPerSample,sizeof(unsigned short),1,fpSave); type[0]='d'; type[1]='a'; type[2]='t'; type[3]='a'; // subchunk2Id // Содержит символы “data” (0x64617461 в big-endian представлении) fwrite(&type, sizeof(char), 4,fpSave); wavSubchunk2Size = 0; //Количество байт в области данных. fwrite(&wavSubchunk2Size, sizeof(unsigned long), 1,fpSave); return 1; } void sdb::writeSampleWavFile(void* data) { fwrite(data, wavLenDataType, wavBlockAlign, fpSave); wavSubchunk2Size = wavSubchunk2Size + wavLenDataType*wavBlockAlign; } void sdb::writeDataBlockWavFile(void* data, unsigned long len) { fwrite(data, wavLenDataType, len, fpSave); wavSubchunk2Size = wavSubchunk2Size + len*wavLenDataType; } // данная функция закрывает аудиофайл и записывает количесвто байт данных. void sdb::closeWavFile(void) { wavChunkSize = wavSubchunk2Size + 44 - 8; fseek(fpSave,4,SEEK_SET); fwrite(&wavChunkSize,4,1,fpSave); fseek(fpSave,40,SEEK_SET); fwrite(&wavSubchunk2Size,4,1,fpSave); fclose(fpSave); } // конструктор sdb::sdb(void) { openAlnBuf = 0; wavBlockAlign = 0; wavSubchunk2Size = 0; wavChunkSize = 0; wavLenDataType = 0; fpSave = NULL; strcat(wavFileName,SDB_WAV_FILE_NAME); dTime = 1.0/(double)SDB_OPENAL_FREQUENCY; allTime = 0.0; // переключатель буферов на первом буфере switchBuffer = 0; // позиция в буферах (сумма) posAllBuffer = 0; // позиции в буфере обнуляем posBufferOne = 0; posBufferTwo = 0; isBufferOneFlag = 0; isBufferTwoFlag = 0; isCreateWavFileFlag = 0; busState = SDB_MAX_DATA; uartSetBaudrate(SDB_UART_BAUDRATE); uartSetBit(SDB_UART_BIT); uartSetStopBit(SDB_UART_STOP_BIT); uartSetParityBit(SDB_UART_PARITY); recordOn(); playAudioOn(); } // деструктор sdb::~sdb() { if (isCreateWavFileFlag == 1) { if (posBufferOne > 0) { if (isWavFileOutput == 1) writeDataBlockWavFile(busDataOne,posBufferOne); #if SDB_WITH_OPENAL == 1 if (isAudioOutput == 1) setBufferOpenAl(busDataOne,posBufferTwo); #endif } else if (posBufferTwo > 0) { if (isWavFileOutput == 1) writeDataBlockWavFile(busDataTwo,posBufferTwo); #if SDB_WITH_OPENAL == 1 if (isAudioOutput == 1) setBufferOpenAl(busDataTwo,posBufferTwo); #endif } if (isWavFileOutput == 1) closeWavFile(); isCreateWavFileFlag = 0; #if SDB_WITH_OPENAL == 1 if (isAudioOutput == 1) { while (1) { // Ждем, когда звук проиграет до конца if (updateOpenAl() == 0) break; } closeOpenAlSound(); destroyOpenAL(); } #endif } } // функция передает данные по шине one wire void sdb::oneWireSendByte(unsigned char data) { for (register unsigned char i = 0; i < 8; i++) { if((data & (1 << i)) == 1 << i) { busState = 0; busDelay(12); busState = SDB_MAX_DATA; busDelay(65); } else { busState = 0; busDelay(65); busState = SDB_MAX_DATA; busDelay(12); } } busState = SDB_MAX_DATA; } // функция передает один байт по шине uart void sdb::uartSendByte(unsigned char data) { unsigned short pBit = 0; // переменная для бита четности // старт бит busState = SDB_MAX_DATA; busDelay(uartT); busState = -SDB_MAX_DATA; // данные for (register unsigned char i = 0; i < 8; i++) { if((data & (1< SDB_UART_BAUDRATE_MAX) baudrate = SDB_UART_BAUDRATE_MAX; uartBaudrate = baudrate; uartT = 1000000 / baudrate; } void sdb::uartSetBit(unsigned char bit) { if (bit > 32) bit = 32; if (bit == 0) bit = 1; if (bit < 8) bit = 8; uartBit = bit; } void sdb::uartSetStopBit(unsigned char bit) { if (bit == 0) bit = 1; uartStopBit = bit; } void sdb::uartSetParityBit(unsigned char state) { if (state > 1) state = 1; uartParityBit = state; } //функция определяет есть ли устройство на шине void sdb::oneWireReset(void) { busState = SDB_MAX_DATA; busDelay(100); busState = 0;//логический "0" busDelay(485);//ждем минимум 480мкс busState = SDB_MAX_DATA; busDelay(65);//ждем минимум 60мкс и смотрим что на шине busState = 0;//логический "0" busDelay(400); busState = SDB_MAX_DATA; busDelay(100); } // функция останавливает шину 1-wire void sdb::oneWireStop(void) { if (isCreateWavFileFlag == 1) { if (posBufferOne > 0) { if (isWavFileOutput == 1) writeDataBlockWavFile(busDataOne,posBufferOne); #if SDB_WITH_OPENAL == 1 if (isAudioOutput == 1) setBufferOpenAl(busDataOne,posBufferOne); #endif } else if (posBufferTwo > 0) { if (isWavFileOutput == 1) writeDataBlockWavFile(busDataTwo,posBufferTwo); #if SDB_WITH_OPENAL == 1 if (isAudioOutput == 1) setBufferOpenAl(busDataTwo,posBufferTwo); #endif } #if SDB_WITH_OPENAL == 1 while (1) { // Ждем, когда звук проиграет до конца if (updateOpenAl() == 0) break; } closeOpenAlSound(); destroyOpenAL(); #endif if (isWavFileOutput == 1) closeWavFile(); isCreateWavFileFlag = 0; } } void sdb::uartStop(void) { if (isCreateWavFileFlag == 1) { if (posBufferOne > 0) { if (isWavFileOutput == 1) writeDataBlockWavFile(busDataOne,posBufferOne); #if SDB_WITH_OPENAL == 1 if (isAudioOutput == 1) setBufferOpenAl(busDataOne,posBufferOne); #endif } else if (posBufferTwo > 0) { if (isWavFileOutput == 1) writeDataBlockWavFile(busDataTwo,posBufferTwo); #if SDB_WITH_OPENAL == 1 if (isAudioOutput == 1) setBufferOpenAl(busDataTwo,posBufferTwo); #endif } #if SDB_WITH_OPENAL == 1 if (isAudioOutput == 1) { while (1) { // Ждем, когда звук проиграет до конца if (updateOpenAl() == 0) break; } closeOpenAlSound(); destroyOpenAL(); } #endif if (isWavFileOutput == 1) closeWavFile(); isCreateWavFileFlag = 0; } } void sdb::setWavFileName(char* filename) { strcat(wavFileName,filename); } void sdb::playAudioOn(void) { if (isCreateWavFileFlag == 0) isAudioOutput = 1; } void sdb::playAudioOff(void) { if (isCreateWavFileFlag == 0) isAudioOutput = 0; } void sdb::recordOn(void) { if (isCreateWavFileFlag == 0) isWavFileOutput = 1; } void sdb::recordOff(void) { if (isCreateWavFileFlag == 0) { if (isAudioOutput == 1) isWavFileOutput = 0; else isWavFileOutput = 1; } }
#ifndef MAIN_H_INCLUDED #define MAIN_H_INCLUDED #define LINUX 0x00 #define WINDOWS 0x01 #define RU 0x00 #define EN 0x01 /// Тип операционой системы #define TYPE_OS WINDOWS /// Язык программы #define LANGUAGE_PROGRAM RU #define UART_BUS 0x01 #define ONE_WIRE_BUS 0x02 #include #include "SoundsDigitalBus.h" #include "stdlib.h" #include #endif // MAIN_H_INCLUDED
#include "main.h" sdb soundsDigitalBus; int main() { static FILE *fp = NULL; // файл с данными char strData[512]; // буфер для строк char strChar = 0; // символ unsigned char busType; // тип цифровой шины int strPos = 0; // позиция в строке int uartBaudrate = 0; // скорость UART int uartBit = 8; int uartStopBit = 0; //int uartParityBit = 0; #if TYPE_OS==WINDOWS and LANGUAGE_PROGRAM==RU setlocale(LC_ALL, "Russian"); printf("Введите скорость UART в бод, или укажите 0, если хотите 1-wire.n"); #else printf("Enter the UART baud rate, or specify 0 if you want 1-wire.n"); #endif printf("UART Baudrate: "); memset(strData,0,512); while(1) { strChar = getchar(); if ((strChar >= '0') && (strChar <= '9')) { strData[strPos++] = strChar; } else break; } uartBaudrate = atoi(strData); if (uartBaudrate == 0) { busType = ONE_WIRE_BUS; } else { busType = UART_BUS; soundsDigitalBus.uartSetBaudrate(uartBaudrate); } printf("n"); if (busType == UART_BUS) { #if TYPE_OS==WINDOWS and LANGUAGE_PROGRAM==RU printf("Введите количество бит UARTn"); #else printf("Enter the number of bits UART.n"); #endif printf("UART bit: "); memset(strData,0,512); while(1) { strChar = getchar(); if ((strChar >= '0') && (strChar <= '9')) { strData[strPos++] = strChar; } else break; } uartBit = atoi(strData); soundsDigitalBus.uartSetBit(uartBit); printf("n"); #if TYPE_OS==WINDOWS and LANGUAGE_PROGRAM==RU printf("Введите количество стоп бит UARTn"); #else printf("Enter the number of stop bits UART.n"); #endif printf("UART stop bit: "); memset(strData,0,512); while(1) { strChar = getchar(); if ((strChar >= '0') && (strChar <= '9')) { strData[strPos++] = strChar; } else break; } uartStopBit = atoi(strData); soundsDigitalBus.uartSetStopBit(uartStopBit); printf("n"); #if TYPE_OS==WINDOWS and LANGUAGE_PROGRAM==RU printf("Использовать бит четности в UART? (Y/n)n"); #else printf("Use the parity bit in the UART? (Y/n)n"); #endif strChar = getchar(); if ((strChar == 'n') || (strChar == 'N') || (strChar == 'т') || (strChar == 'Т')) { soundsDigitalBus.uartSetParityBit(0); printf("not usedn"); } else { soundsDigitalBus.uartSetParityBit(1); printf("Yes, usen"); } getchar(); printf("n"); } FILE_M: printf("n"); #if TYPE_OS==WINDOWS printf("Укажите файл для преобразования его в запись цифровой шины.n"); printf("Например: D: \ Games \ SR2 \ Rangers.txtn"); printf("Файл: "); #else printf("Specify the file to convert it to record digital bus.n"); printf("For example: D: \ Games \ SR2 \ Rangers.txtn"); printf("File: "); #endif memset(strData,0,512); strPos = 0; while(1) { strChar = getchar(); if (strChar != 'n') { strData[strPos++] = strChar; } else break; } fp = fopen(strData,"rb"); if (fp == NULL) { printf("n"); #if TYPE_OS==WINDOWS printf("Ошибка! Файл %s не найден!n",strData); printf("Поробуйте правильно указать путь до файла.n"); printf("...n"); #else printf("Error! File %s not found!n",strData); printf("Try to correctly specify the path to the file.n"); printf("...n"); #endif getchar(); goto FILE_M; } //soundsDigitalBus.setWavFileName(strData); printf("n"); #if SDB_WITH_OPENAL == 1 #if TYPE_OS==WINDOWS printf("Воспроизводить аудио во время работы цифровой шины? (Y/n)n"); #else printf("Play audio while working digital bus? (Y/n)n"); #endif strChar = getchar(); if ((strChar == 'n') || (strChar == 'N') || (strChar == 'т') || (strChar == 'Т')) { soundsDigitalBus.playAudioOff(); printf("not usedn"); } else { soundsDigitalBus.playAudioOn(); printf("Yes, usen"); } getchar(); printf("n"); #if TYPE_OS==WINDOWS printf("Записывать аудио во время работы цифровой шины? (Y/n)n"); #else printf("Record audio while working digital bus? (Y/n)n"); #endif strChar = getchar(); if ((strChar == 'n') || (strChar == 'N') || (strChar == 'т') || (strChar == 'Т')) { soundsDigitalBus.recordOff(); printf("not usedn"); } else { soundsDigitalBus.recordOn(); printf("Yes, usen"); } getchar(); #else soundsDigitalBus.recordOn(); #endif printf("n"); #if TYPE_OS==WINDOWS printf("Преобразование начато.n"); #else printf("The transformation started.n"); #endif unsigned char uartData[8]; if (busType == ONE_WIRE_BUS) { soundsDigitalBus.oneWireReset(); } while(1) { if (fread(uartData,sizeof(unsigned char),1,fp) > 0) { if (busType == UART_BUS) { if (uartBit == 8) { soundsDigitalBus.uartSendByte(uartData[0]); } else { soundsDigitalBus.uartSend(uartData[0]); } } else if (busType == ONE_WIRE_BUS) { soundsDigitalBus.oneWireSendByte(uartData[0]); } } else break; } fclose(fp); if (busType == ONE_WIRE_BUS) { soundsDigitalBus.oneWireStop(); } else if (busType == UART_BUS) { soundsDigitalBus.uartStop(); } #if TYPE_OS==WINDOWS printf("Преобразование завершено.n"); #else printf("Conversion completed.n"); #endif return 0; //soundsDigitalBus.oneWireReset(); soundsDigitalBus.uartSetBaudrate(1200); for (int i = 0; i < 256; i ++) { for (int len = 0; len < 8; len++) { soundsDigitalBus.uartSendByte(i); } printf("%dn",i); } soundsDigitalBus.oneWireStop(); return 0; }
P.S. Заметил ошибку, что в исходном коде стартовый бит равен логической 1, а не 0, а стоповый равен 0, а не 1. Кому необходимо принципиальное соотвествение звукового сигнала реальности, может исправить ошибку сам.
Источник