Arduino之US015高分辨超声波测距模块

超声波测距原理

超声波测距原理是在超声波发射装置发出超声波,它的根据是接收器接到超声波时的时间差,与雷达测距原理相似。 超声波发射器向某一方向发射超声波,在发射时刻的同时开始计时,超声波在空气中传播,途中碰到障碍物就立即返回来,超声波接收器收到反射波就立即停止计时。(超声波在空气中的传播速度为340m/s,根据计时器记录的时间t(秒),就可以计算出发射点距障碍物的距离(s),即:s=340t/2)

Arduino之GY-30光照传感器

GY-30 光照传感器

数字光强度检测模块:GY-30

  • 采用ROHM原装BH1750FVI芯片
  • 供电电源 :3-5v
  • 光照度范围:0-65535 lx
  • 传感器内置16bitAD转换器
  • 直接数字输出,省略复杂的计算,省略标定
  • 不区分环境光源
  • 接近于视觉灵敏度的分光特性
  • 可对广泛的亮度进行1勒克斯的高精度测定

代码

采用IIC通讯方式,GY-30VCC接+5V,GND接地。GY-30 SDA 、SCL分别接A4、 A5

Arduino之DHT11温湿度传感器模块

DHT11 温湿度传感器

DHT11 是一款温湿度传感器,可以用来测试环境温湿度,该传感器的的温度测量范围为 0 ~ 50°C,误差为 2 °C;湿度测量范围为在 0°C时为30%-90%RH,环境温度为 25°C时,湿度测量范围为20%-90%RH,在50°C时,测量范围是20%-80%。

算数独

闲暇的时候写的小程序,从map输入数独的题目后自动计算。

#include "stdafx.h"

#include <vector>
#include <map>
#include <iostream>
#include <assert.h>

// 获取行index
std::vector<int> askRow(int index)
{
    std::vector<int> rownum;

    auto rowindex = index / 10;
    for (int i = 0; i < 9; i++)
    {
        rownum.push_back(rowindex * 10 + i);
    }
    return rownum;
}

// 获取列index
std::vector<int> askCol(int index)
{
    std::vector<int> colnum;

    auto colindex = index % 10;
    for (int i = 0; i < 9; i++)
    {
        colnum.push_back(i * 10 + colindex);
    }
    return colnum;
}

// 获取宫index
std::vector<int> askBlock(int index)
{
    std::vector<std::vector<int>> blocknum = {
        {0,1,2,10,11,12,20,21,22},
        {3,4,5,13,14,15,23,24,25},
        {6,7,8,16,17,18,26,27,28},
        {30,31,32,40,41,42,50,51,52},
        {33,34,35,43,44,45,53,54,55},
        {36,37,38,46,47,48,56,57,58},
        {60,61,62,70,71,72,80,81,82},
        {63,64,65,73,74,75,83,84,85},
        {66,67,68,76,77,78,86,87,88},
    };

    for (const std::vector<int>& item : blocknum)
    {
        if (item.end() != std::find(item.begin(), item.end(), index))
            return item;
    }
    assert(false);
    return std::vector<int>();
}

// 检查冲突(入参为格子的值,而非index)
bool check(const std::vector<char>& block)
{
    char checknum[9] = { 0 };
    for (auto item : block)
    {
        if (item == 0)
            continue;

        // 同一位置已经有值了
        if (checknum[item - 1] == 1)
            return false;

        // 占位
        checknum[item - 1] = 1;
    }
    return true;
}

// 获取一个检查数据
std::vector<char> getBlock(const std::vector<char>& table, const std::vector<int>& block)
{
    assert(block.size() == 9);

    std::vector<char> blockData;
    for (size_t i = 0; i < block.size(); ++i)
    {
        blockData.push_back(table.at(block.at(i)));
    }
    return blockData;
}

bool calcBackup(std::vector<char>& table, std::vector<std::pair<char, std::vector<char>>>& backupmap)
{
    // 侯选数
    backupmap.clear();
    for (int index = 0; index < 90; ++index)
    {
        if (index % 10 == 9)
            continue;

        if (table.at(index) > 0)
            continue;

        // 获取三种类型的数据集
        auto blockRow = askRow(index);
        auto blcokDataRow = getBlock(table, blockRow);
        auto blockCol = askCol(index);
        auto blcokDataCol = getBlock(table, blockCol);
        auto block = askBlock(index);
        auto blcokData = getBlock(table, block);

        // 获取每个格子的候选数
        std::vector<char> vec;
        for (int i = 1; i < 10; i++)
        {
            if (blcokDataRow.end() == std::find(blcokDataRow.begin(), blcokDataRow.end(), i) &&
                blcokDataCol.end() == std::find(blcokDataCol.begin(), blcokDataCol.end(), i) &&
                blcokData.end() == std::find(blcokData.begin(), blcokData.end(), i))
                vec.push_back(i);
        }

        // 如果只有一个候选数,则重算
        assert(vec.size() > 0);
        if (vec.size() == 1)
        {
            table.at(index) = vec[0];
            return true;
        }
        backupmap.push_back(std::make_pair(index, vec));
    }
    return false;
}

// 递归,一个个的试
bool calc(std::vector<char>& table, const std::vector<std::pair<char, std::vector<char>>>& backupmap, int num, int index)
{
    int currentIndex = backupmap.at(num).first;
    table.at(currentIndex) = backupmap.at(num).second.at(index);

    auto blockRow = askRow(currentIndex);
    auto blockCol = askCol(currentIndex);
    auto block = askBlock(currentIndex);
    if (check(getBlock(table, block)) && check(getBlock(table, blockRow)) && check(getBlock(table, blockCol)))
    {
        if (num >= backupmap.size() - 1)
        {
            // 计算到最后一格,出现全部备选数据相匹配的情况
            return true;
        }
        else
        {
            // 当前格子匹配正常,继续计算下一个
            for (int index = 0; index < backupmap.at(num + 1).second.size(); ++index)
            {
                if (calc(table, backupmap, num + 1, index))
                {
                    return true;
                }
            }
        }
    }
    table.at(currentIndex) = 0;
    return false;
}

void prinfTable(const std::vector<char>& table)
{
    for (int row = 0; row < 9; ++row)
    {
        if (row % 3 == 0)
        {
            printf("------------------------------------------ \n");
        }

        printf("%4d%4d%4d | %4d%4d%4d | %4d%4d%4d \n", table[row * 10], table[row * 10 + 1], table[row * 10 + 2],
            table[row * 10 + 3], table[row * 10 + 4], table[row * 10 + 5],
            table[row * 10 + 6], table[row * 10 + 7], table[row * 10 + 8]);
    }
}

bool fill(const std::map<char, char>& origin, std::vector<char>& table)
{
    for (auto item : origin)
    {
        table.at(item.first) = item.second;
    }

    int i = 0;
    std::vector<std::pair<char, std::vector<char>>> backupmap;
    while (calcBackup(table, backupmap))
    {
        if (i++ > 90)
            break;
    }

    if (backupmap.size() > 0)
    {
        for (int index = 0; index < backupmap.front().second.size(); ++index)
        {
            if (calc(table, backupmap, 0, index))
            {
                return true;
            }
        }
        return false;
    }
    return true;
}

int main()
{
    std::map<char, char> origin;
    origin.insert(std::make_pair(12, 1));
    origin.insert(std::make_pair(15, 9));
    origin.insert(std::make_pair(18, 7));
    origin.insert(std::make_pair(20, 7));
    origin.insert(std::make_pair(22, 9));
    origin.insert(std::make_pair(23, 4));
    origin.insert(std::make_pair(27, 2));
    origin.insert(std::make_pair(28, 3));
    origin.insert(std::make_pair(32, 4));
    origin.insert(std::make_pair(33, 7));
    origin.insert(std::make_pair(36, 6));
    origin.insert(std::make_pair(43, 1));
    origin.insert(std::make_pair(44, 5));
    origin.insert(std::make_pair(47, 8));
    origin.insert(std::make_pair(55, 4));
    origin.insert(std::make_pair(61, 2));
    origin.insert(std::make_pair(66, 7));
    origin.insert(std::make_pair(67, 3));
    origin.insert(std::make_pair(70, 5));
    origin.insert(std::make_pair(71, 8));
    origin.insert(std::make_pair(74, 1));
    origin.insert(std::make_pair(78, 2));
    origin.insert(std::make_pair(84, 4));
    origin.insert(std::make_pair(85, 3));

    std::vector<char> table(90, 0);
    if (fill(origin, table))
    {
        std::cout << "happy end" << std::endl;
        prinfTable(table);
    }
    else
    {
        std::cout << "sorry" << std::endl;
    }

    getchar();
    return 0;
}

前端矩阵 (matrix) 封装

使用 canvas 画布来操控图形或者图片的二维变化的方式一般是平移、缩放、和旋转。canvas 已相应提供了相关的 api。如:translate(), scale() 和 rotate(),但这些功能无法统一处理并且无法描述当前画布的处于某种状态。为了实现这种统一连贯性的状态描述,canvas 给我们提供了另外一种思路及方法,即使用:transform() / setTransform();因为画布上的每个对象都拥有一个当前的 3 x 3 变换矩阵,都可以使用一个 3 x 3 矩阵来描述当前状态,其实是 2 x 3 矩阵,但为了便于计算,人为添加第三行 0 0 1 变成 3 x 3 矩阵。费话不多话,下面直接看矩阵变换的已封装好的功能,为了便于读者理解,每一步都有详细解释及介绍。

boost b2 参数说明

命令参数

b2 命令的功能强大,用起来也比较复杂,因此在使用之前,最好先查看一下该命令的帮助:

b2.exe --help

stage/install

stage 表示只生成库(dll 和 lib),install 还会生成包含头文件的 include 目录。推荐使用 stage,因为 install 生成的 include 目录实际就是源码包下的 boost 目录,需要 include 的时候可以直接使用,不需要再次生成,这样可以节省大量的编译时间。

合并两个 Git 仓库,并保留源仓库的所有提交记录

需求

  • 有2个 git 仓库:repo1、repo2;
  • 想将 repo1 中的文件移入 repo2;
  • repo1 的提交记录要保留;

实现

将 repo1 作为远程仓库,添加到 repo2 中,并设置别名为 other:

切换至 repo2 仓库,并执行以下命令:

如何从 GitHub 上下载单个文件夹?

今天要从GitHub上下载东西,结果突然发现GitHub只提供整项目下载,而不支持选择某一个子文件夹下载。

搜索答案,找到了一种方法如下:

  • 先在GitHub上打开需要下载的子文件夹,记下浏览器里的路径
  • 然后,将路径里面的 /tree/master/ 替换为 /trunk/
  • 最后到SVN里面,选择检出这个修改后的url

如果不是GIT的master分支,则将 /tree/master/ 替换为 /branches/branchname/ 其中 branchname 为分支名

如何设计高效的C++类

一直以来,使用C++面向对象机制,主要是为了其封装和多态特性。往往设计类时,只是为了功能的堆砌,没有考虑的更加深入。

之前也阅读过《Effective C++》,只是那时是在学生时代。如今工作了,重新阅读,有不少新的感悟。最关键的是,能从更高的视角去设计程序,之前杂乱无序的点与点,逐渐连接成一条条线。希望后续能够成面、成立体。

使用.NET Core创建Windows服务(三) - 使用.NET Core工作器方式

使用微软推荐方式

使用Topshelf方式

安装步骤

这里首先你要确保你已经安装了.NET Core 3.0或以上版本。在我编写这篇文章的时候, .NET Core 3.1刚刚发布,Visual Studio应该会提示你升级到最新版本。但是如果你想要在.NET Core 2.x项目中使用这个方式,应该是行不通的。