1. 程式人生 > 其它 >UHD C/C++ 程式設計例項 USRP傳送、接收資料

UHD C/C++ 程式設計例項 USRP傳送、接收資料

技術標籤:硬體USRP

UHD C/C++ 程式設計例項 USRP傳送、接收資料

如有相關問題,歡迎隨時討論交流 [email protected]

1. UHD庫函式簡介

1.1 傳送函式

新建一個usrp裝置
std::string args = " "; args指定USRP地址,配置USRP引數等
uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);

設定時鐘源和時鐘頻率
std::string ref = "internal"; // internal, external, MIMO.


usrp->set_clock_source(ref);
double rate = 40e6;
usrp->set_master_clock_rate(rate);

usrp->get_clock_source() //獲取當前的時鐘源
usrp->get_clock_sources() //獲取所有可用的時鐘源
usrp->get_master_clock_rate(); //獲取時鐘頻率

設定取樣率
double samp_rate = 20e6;
usrp->set_tx_rate(samp_rate);

usrp->get_tx_rate() //獲取當前的取樣率
usrp->get_tx_rates() //獲取取樣率的取樣範圍

設定發射中心頻點
double freq = 2.412e9;
usrp->set_tx_freq(freq);

usrp->get_fe_tx_freq_range();
usrp->get_tx_freq();
usrp->get_tx__freq_range();

設定發射增益
double tx_gain = 60;
usrp->set_tx_gain(tx_gain);

設定發射天線
預設情況下無需設定發射天線,如需指定特定發射天線時設定。
usrp->set_tx_antenna(0);
usrp->get_tx_antenna();
usrp->get_tx_antennas();

建立傳送流
新建傳送流引數
std::string cpu_format = "fc32";
目前cpu_format支援的型別有:fc64 - complex fc32 - complex sc16 - complex sc8 - complex
std::string wire_format = "sc16";
目前wire_format支援的型別有:sc16 - Q16 I16 sc8 - Q8_1 I8_1 Q8_0 I8_0

uhd::stream_args_t stream_args(cpu_format, wire_format);
uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args);

中頻資料管理
uhd::tx_metada_t md; //結構體描述接收到的中頻訊號
md.start_of_burst = false; // 設定為真的時候傳送第一個資料包
md.end_of_burst = false; // 設定為真的時候傳送最後一個數據包
md.has_time_spec = false; // 設定為false時立即傳送,設定為真的時候在特定時間傳送

1.2 接收函式

建立一個usrp
std::string args = " ";
uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);

設定時鐘源和時鐘頻率
std::string ref = "internal"; //internal, external and MIMO
usrp->set_clock_source(ref);

double clock_rate = 40e6;
usrp->set_master_clock_rate(clock_rate);

設定取樣率
double rate = 20e6;
usrp->set_rx_rate(rate);

設定中心頻率
double freq = 2.412e9;
usrp->set_rx_freq(freq);

設定增益
double rx_gain = 50;
usrp->set_rx_gain(rx_gain);

建立接收流
std::string cpu_format = "fc32";
std::string wire_format = "sc16";
uhd::stream_args_t stream_args(cpu_format, wire_format);
uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args);

設定接收模式
uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);

//UHD_STREAM_MODE_START_CONTINUOUS=97,//UHD_STREAM_MODE_STOP_CONTINUOUS=111,//UHD_STREAM_MODE_NUM_SAMPS_AND_DONE=100,//UHD_STREAM_MODE_NUM_SAMPS_AND_MORE=109

stream_cmd.num_samps = 1000; // 接收取樣點數
stream_cmd.stream_now = true; //現在開始接收
rx_stream->issue_stream_cmd(stream_cmd); //配置rx_stream引數

2. USRP傳送資料

  程式碼實現USRP傳送二進位制檔案802.11a_BUPT41.seg內的資料。裡面的資料為float complex型別,複數的實部和虛部交替儲存。即如下圖所示。使用者可以把要傳送的資料生成對應的二進位制檔案,也可以直接寫成陣列放在程式碼中。注意:float型別資料的單位1就是 “1”。
這裡寫圖片描述

原始碼

#include <uhd/usrp/multi_usrp.hpp>
#include <signal.h>

#define SAMPLE_PER_BUFF 2000

int stop_signal_called = 0;
void sig_int_handle(int)
{
    stop_signal_called = 1;
    printf("stop tx.........\n");
    exit(0);
}

int main()
{
    std::string addr_args = " ";
    uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(addr_args);
    printf("Create a usrp......\n");

    // set the ref and clock rate
    std::string ref = "internal";
    usrp->set_clock_source(ref);

    float clock_rate = 40e6;
    usrp->set_master_clock_rate(clock_rate);
    printf("set the  clock rate %0.2f \n", usrp->get_master_clock_rate() );

    // set the sample rate
    float samp_rate = 20e6;
    usrp->set_tx_rate(samp_rate);
    printf("set the tx sample rate to %0.2f \n", usrp->get_tx_rate());

    // set the center frequency
    float center_freq = 2.412e9;
    usrp->set_tx_freq(center_freq);
    printf("set the tx center freq to %0.2f \n", usrp->get_tx_freq());

    // set the rf gain
    float tx_gain = 90;
    usrp->set_tx_gain(tx_gain);
    printf("set the tx gain to %0.2f \n", usrp->get_tx_gain());


    // create a tx stream
    std::string cpu_format = "fc32";
    std::string wire_format = "sc16";
    uhd::stream_args_t stream_args(cpu_format, wire_format);
    uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args);

    uhd::tx_metadata_t md;

    // catch the INT signal
    signal(SIGINT, sig_int_handle);
    float read_buff[SAMPLE_PER_BUFF * 2] = {0};

    while(!stop_signal_called)
    {
        FILE *fp = fopen("802.11a_BUPT41.seg", "rb");
        md.start_of_burst = false;
        md.end_of_burst = false;


        while( (!md.end_of_burst) && (!stop_signal_called) )
        {
            int read_length = 0;
            if( (read_length = fread(read_buff, sizeof(uint32_t), SAMPLE_PER_BUFF * 2, fp) ) == (SAMPLE_PER_BUFF * 2) )
            {
                //int index;
                //for(index = 0; index < SAMPLE_PER_BUFF * 2; index++)
                //    printf("%0.2f ", read_buff[index]);
                //puts("");

                //md.start_of_burst = true;
                tx_stream->send(read_buff, SAMPLE_PER_BUFF, md);
                //md.start_of_burst = false;
                //sleep(1);
            }
            else if(read_length >= 0)
            {
                md.end_of_burst = true;
            }
        }

        fclose(fp);
    }


    return 0;
}

編譯
g++ 編譯時需要連結uhd庫,系統需提前安裝UHD驅動。具體過程參見之前部落格。Ubuntu14.04 原始碼安裝 UHD3.8.0
g++ tx.cpp -o tx -luhd

3. USRP接收資料

  啟動USRP,並使USRP一直接收資料。

原始碼

#include <uhd/usrp/multi_usrp.hpp>
#include <csignal>

#define SAMPLE_PER_BUFF 2000

int stop_signal_called = false;
void sig_int_handle()
{
    stop_signal_called = true;
}

int main()
{
    std::string addr_args = " ";
    uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(addr_args);

    // set the clock source and clock rate
    std::string ref = "internal";
    usrp->set_clock_source(ref);

    float clock_rate = 40e6;
    usrp->set_master_clock_rate(clock_rate);
    printf("set the  clock rate %0.2f \n", usrp->get_master_clock_rate() );

    // set the sample rate
    float samp_rate = 20e6;
    usrp->set_rx_rate(samp_rate);
    printf("set the tx sample rate to %0.2f \n", usrp->get_rx_rate());

    // set the center frequency
    float center_freq = 2.412e9;
    usrp->set_rx_freq(center_freq);
    printf("set the tx center freq to %0.2f \n", usrp->get_rx_freq());

    // set the rf gain
    float rx_gain = 80;
    usrp->set_rx_gain(rx_gain);
    printf("set the tx gain to %0.2f \n", usrp->get_rx_gain());

    std::string cpu_format = "fc32";
    std::string wire_format = "sc16";
    uhd::stream_args_t stream_args(cpu_format, wire_format);
    uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args);

    uhd::rx_metadata_t md;

    //uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE);
    uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
    stream_cmd.num_samps = SAMPLE_PER_BUFF;
    stream_cmd.stream_now = true;
    //stream_cmd.time_spec = uhd::time_spec_t();
    stream_cmd.time_spec = usrp->get_time_now();
    rx_stream->issue_stream_cmd(stream_cmd);

    uint32_t buff[SAMPLE_PER_BUFF*2] = {0};
    unsigned long long num_total_samps = 0;

    while(!stop_signal_called)
    {
        //int num_rx_samps = rx_stream->recv(buff, SAMPLE_PER_BUFF, md);
        memset(buff, 0, SAMPLE_PER_BUFF * sizeof(uint32_t));
        int num_rx_samps = rx_stream->recv(buff, SAMPLE_PER_BUFF, md, 3.0, false);
        if(md.error_code == uhd::rx_metadata_t::ERROR_CODE_TIMEOUT)
        {
            printf("Timeout while streaming......\n");
            break;
        }
        if(md.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW)
        {
            printf("Overflowing while stream......\n");
            continue;
        }
        if(md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE)
        {
            //printf("Receive error: %s \n", md.strerror());
            continue;
        }

    //printf("num_rx_samps = %d \n",num_rx_samps);
        num_total_samps += num_rx_samps;

    }
    printf("num_total_samps = %d \n", num_total_samps);

    stream_cmd.stream_mode = uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS;
    rx_stream->issue_stream_cmd(stream_cmd);

    return 0;
}

編譯

g++ 編譯時需要連結uhd庫,系統需提前安裝UHD驅動。具體過程參見之前部落格。Ubuntu14.04 原始碼安裝 UHD3.8.0
g++ rx.cpp -o rx -luhd

4. 結論

  以上程式碼在Ubuntu上採用USRP B200測試通過。
  掌握UHD庫函式的使用、g++ 連結 UHD庫等是基於USRP開發軟體無線電專案的基礎。之後,我們可以進一步設計傳送程式和接收程式,用USRP搭建一套SDR 收發系統。