2198 lines
214 KiB
HTML
2198 lines
214 KiB
HTML
|
<!DOCTYPE html><html lang="fr">
|
|||
|
<head><meta charset="utf-8">
|
|||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|||
|
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"><title>Module sans fil nRF24L01+PA-LNA 2.4Ghz et interface avec Arduino - YannStatic</title>
|
|||
|
|
|||
|
<meta name="description" content="Module sans fil nRF24L01+PA-LNA">
|
|||
|
<link rel="canonical" href="https://static.rnmkcy.eu/2020/08/04/Module-sans-fil-nRF24L01-et-interface-avec-Arduino.html"><link rel="alternate" type="application/rss+xml" title="YannStatic" href="/feed.xml">
|
|||
|
|
|||
|
<!-- - include head/favicon.html - -->
|
|||
|
<link rel="shortcut icon" type="image/png" href="/assets/favicon/favicon.png"><link rel="stylesheet" href="/assets/css/main.css"><link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" ><!-- start custom head snippets --><link rel="stylesheet" href="/assets/css/expand.css">
|
|||
|
<!-- end custom head snippets --><script>(function() {
|
|||
|
window.isArray = function(val) {
|
|||
|
return Object.prototype.toString.call(val) === '[object Array]';
|
|||
|
};
|
|||
|
window.isString = function(val) {
|
|||
|
return typeof val === 'string';
|
|||
|
};
|
|||
|
|
|||
|
window.hasEvent = function(event) {
|
|||
|
return 'on'.concat(event) in window.document;
|
|||
|
};
|
|||
|
|
|||
|
window.isOverallScroller = function(node) {
|
|||
|
return node === document.documentElement || node === document.body || node === window;
|
|||
|
};
|
|||
|
|
|||
|
window.isFormElement = function(node) {
|
|||
|
var tagName = node.tagName;
|
|||
|
return tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA';
|
|||
|
};
|
|||
|
|
|||
|
window.pageLoad = (function () {
|
|||
|
var loaded = false, cbs = [];
|
|||
|
window.addEventListener('load', function () {
|
|||
|
var i;
|
|||
|
loaded = true;
|
|||
|
if (cbs.length > 0) {
|
|||
|
for (i = 0; i < cbs.length; i++) {
|
|||
|
cbs[i]();
|
|||
|
}
|
|||
|
}
|
|||
|
});
|
|||
|
return {
|
|||
|
then: function(cb) {
|
|||
|
cb && (loaded ? cb() : (cbs.push(cb)));
|
|||
|
}
|
|||
|
};
|
|||
|
})();
|
|||
|
})();
|
|||
|
(function() {
|
|||
|
window.throttle = function(func, wait) {
|
|||
|
var args, result, thisArg, timeoutId, lastCalled = 0;
|
|||
|
|
|||
|
function trailingCall() {
|
|||
|
lastCalled = new Date;
|
|||
|
timeoutId = null;
|
|||
|
result = func.apply(thisArg, args);
|
|||
|
}
|
|||
|
return function() {
|
|||
|
var now = new Date,
|
|||
|
remaining = wait - (now - lastCalled);
|
|||
|
|
|||
|
args = arguments;
|
|||
|
thisArg = this;
|
|||
|
|
|||
|
if (remaining <= 0) {
|
|||
|
clearTimeout(timeoutId);
|
|||
|
timeoutId = null;
|
|||
|
lastCalled = now;
|
|||
|
result = func.apply(thisArg, args);
|
|||
|
} else if (!timeoutId) {
|
|||
|
timeoutId = setTimeout(trailingCall, remaining);
|
|||
|
}
|
|||
|
return result;
|
|||
|
};
|
|||
|
};
|
|||
|
})();
|
|||
|
(function() {
|
|||
|
var Set = (function() {
|
|||
|
var add = function(item) {
|
|||
|
var i, data = this._data;
|
|||
|
for (i = 0; i < data.length; i++) {
|
|||
|
if (data[i] === item) {
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
this.size ++;
|
|||
|
data.push(item);
|
|||
|
return data;
|
|||
|
};
|
|||
|
|
|||
|
var Set = function(data) {
|
|||
|
this.size = 0;
|
|||
|
this._data = [];
|
|||
|
var i;
|
|||
|
if (data.length > 0) {
|
|||
|
for (i = 0; i < data.length; i++) {
|
|||
|
add.call(this, data[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
Set.prototype.add = add;
|
|||
|
Set.prototype.get = function(index) { return this._data[index]; };
|
|||
|
Set.prototype.has = function(item) {
|
|||
|
var i, data = this._data;
|
|||
|
for (i = 0; i < data.length; i++) {
|
|||
|
if (this.get(i) === item) {
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
return false;
|
|||
|
};
|
|||
|
Set.prototype.is = function(map) {
|
|||
|
if (map._data.length !== this._data.length) { return false; }
|
|||
|
var i, j, flag, tData = this._data, mData = map._data;
|
|||
|
for (i = 0; i < tData.length; i++) {
|
|||
|
for (flag = false, j = 0; j < mData.length; j++) {
|
|||
|
if (tData[i] === mData[j]) {
|
|||
|
flag = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
if (!flag) { return false; }
|
|||
|
}
|
|||
|
return true;
|
|||
|
};
|
|||
|
Set.prototype.values = function() {
|
|||
|
return this._data;
|
|||
|
};
|
|||
|
return Set;
|
|||
|
})();
|
|||
|
|
|||
|
window.Lazyload = (function(doc) {
|
|||
|
var queue = {js: [], css: []}, sources = {js: {}, css: {}}, context = this;
|
|||
|
var createNode = function(name, attrs) {
|
|||
|
var node = doc.createElement(name), attr;
|
|||
|
for (attr in attrs) {
|
|||
|
if (attrs.hasOwnProperty(attr)) {
|
|||
|
node.setAttribute(attr, attrs[attr]);
|
|||
|
}
|
|||
|
}
|
|||
|
return node;
|
|||
|
};
|
|||
|
var end = function(type, url) {
|
|||
|
var s, q, qi, cbs, i, j, cur, val, flag;
|
|||
|
if (type === 'js' || type ==='css') {
|
|||
|
s = sources[type], q = queue[type];
|
|||
|
s[url] = true;
|
|||
|
for (i = 0; i < q.length; i++) {
|
|||
|
cur = q[i];
|
|||
|
if (cur.urls.has(url)) {
|
|||
|
qi = cur, val = qi.urls.values();
|
|||
|
qi && (cbs = qi.callbacks);
|
|||
|
for (flag = true, j = 0; j < val.length; j++) {
|
|||
|
cur = val[j];
|
|||
|
if (!s[cur]) {
|
|||
|
flag = false;
|
|||
|
}
|
|||
|
}
|
|||
|
if (flag && cbs && cbs.length > 0) {
|
|||
|
for (j = 0; j < cbs.length; j++) {
|
|||
|
cbs[j].call(context);
|
|||
|
}
|
|||
|
qi.load = true;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
var load = function(type, urls, callback) {
|
|||
|
var s, q, qi, node, i, cur,
|
|||
|
_urls = typeof urls === 'string' ? new Set([urls]) : new Set(urls), val, url;
|
|||
|
if (type === 'js' || type ==='css') {
|
|||
|
s = sources[type], q = queue[type];
|
|||
|
for (i = 0; i < q.length; i++) {
|
|||
|
cur = q[i];
|
|||
|
if (_urls.is(cur.urls)) {
|
|||
|
qi = cur;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
val = _urls.values();
|
|||
|
if (qi) {
|
|||
|
callback && (qi.load || qi.callbacks.push(callback));
|
|||
|
callback && (qi.load && callback());
|
|||
|
} else {
|
|||
|
q.push({
|
|||
|
urls: _urls,
|
|||
|
callbacks: callback ? [callback] : [],
|
|||
|
load: false
|
|||
|
});
|
|||
|
for (i = 0; i < val.length; i++) {
|
|||
|
node = null, url = val[i];
|
|||
|
if (s[url] === undefined) {
|
|||
|
(type === 'js' ) && (node = createNode('script', { src: url }));
|
|||
|
(type === 'css') && (node = createNode('link', { rel: 'stylesheet', href: url }));
|
|||
|
if (node) {
|
|||
|
node.onload = (function(type, url) {
|
|||
|
return function() {
|
|||
|
end(type, url);
|
|||
|
};
|
|||
|
})(type, url);
|
|||
|
(doc.head || doc.body).appendChild(node);
|
|||
|
s[url] = false;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
return {
|
|||
|
js: function(url, callback) {
|
|||
|
load('js', url, callback);
|
|||
|
},
|
|||
|
css: function(url, callback) {
|
|||
|
load('css', url, callback);
|
|||
|
}
|
|||
|
};
|
|||
|
})(this.document);
|
|||
|
})();
|
|||
|
</script><script>
|
|||
|
(function() {
|
|||
|
var TEXT_VARIABLES = {
|
|||
|
version: '2.2.6',
|
|||
|
sources: {
|
|||
|
font_awesome: 'https://use.fontawesome.com/releases/v5.0.13/css/all.css',
|
|||
|
jquery: '/assets/js/jquery.min.js',
|
|||
|
leancloud_js_sdk: '//cdn.jsdelivr.net/npm/leancloud-storage@3.13.2/dist/av-min.js',
|
|||
|
chart: 'https://cdn.bootcss.com/Chart.js/2.7.2/Chart.bundle.min.js',
|
|||
|
gitalk: {
|
|||
|
js: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.js',
|
|||
|
css: 'https://cdn.bootcss.com/gitalk/1.2.2/gitalk.min.css'
|
|||
|
},
|
|||
|
valine: 'https://unpkg.com/valine/dist/Valine.min.js'
|
|||
|
},
|
|||
|
site: {
|
|||
|
toc: {
|
|||
|
selectors: 'h1,h2,h3'
|
|||
|
}
|
|||
|
},
|
|||
|
paths: {
|
|||
|
search_js: '/assets/search.js'
|
|||
|
}
|
|||
|
};
|
|||
|
window.TEXT_VARIABLES = TEXT_VARIABLES;
|
|||
|
})();
|
|||
|
</script>
|
|||
|
</head>
|
|||
|
<body>
|
|||
|
<div class="root" data-is-touch="false">
|
|||
|
<div class="layout--page js-page-root"><!----><div class="page__main js-page-main page__viewport hide-footer has-aside has-aside cell cell--auto">
|
|||
|
|
|||
|
<div class="page__main-inner"><div class="page__header d-print-none"><header class="header"><div class="main">
|
|||
|
<div class="header__title">
|
|||
|
<div class="header__brand"><svg id="svg" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="478.9473684210526" viewBox="0, 0, 400,478.9473684210526"><g id="svgg"><path id="path0" d="M308.400 56.805 C 306.970 56.966,303.280 57.385,300.200 57.738 C 290.906 58.803,278.299 59.676,269.200 59.887 L 260.600 60.085 259.400 61.171 C 258.010 62.428,256.198 63.600,255.645 63.600 C 255.070 63.600,252.887 65.897,252.598 66.806 C 252.460 67.243,252.206 67.600,252.034 67.600 C 251.397 67.600,247.206 71.509,247.202 72.107 C 247.201 72.275,246.390 73.190,245.400 74.138 C 243.961 75.517,243.598 76.137,243.592 77.231 C 243.579 79.293,241.785 83.966,240.470 85.364 C 239.176 86.740,238.522 88.365,237.991 91.521 C 237.631 93.665,236.114 97.200,235.554 97.200 C 234.938 97.200,232.737 102.354,232.450 104.472 C 232.158 106.625,230.879 109.226,229.535 110.400 C 228.933 110.926,228.171 113.162,226.434 119.500 C 226.178 120.435,225.795 121.200,225.584 121.200 C 225.373 121.200,225.200 121.476,225.200 121.813 C 225.200 122.149,224.885 122.541,224.500 122.683 C 223.606 123.013,223.214 123.593,223.204 124.600 C 223.183 126.555,220.763 132.911,219.410 134.562 C 218.443 135.742,217.876 136.956,217.599 138.440 C 217.041 141.424,215.177 146.434,214.532 146.681 C 214.240 146.794,214.000 147.055,214.000 147.261 C 214.000 147.467,213.550 148.086,213.000 148.636 C 212.450 149.186,212.000 149.893,212.000 150.208 C 212.000 151.386,208.441 154.450,207.597 153.998 C 206.319 153.315,204.913 150.379,204.633 147.811 C 204.365 145.357,202.848 142.147,201.759 141.729 C 200.967 141.425,199.200 137.451,199.200 135.974 C 199.200 134.629,198.435 133.224,196.660 131.311 C 195.363 129.913,194.572 128.123,193.870 125.000 C 193.623 123.900,193.236 122.793,193.010 122.540 C 190.863 120.133,190.147 118.880,188.978 115.481 C 188.100 112.928,187.151 111.003,186.254 109.955 C 185.358 108.908,184.518 107.204,183.847 105.073 C 183.280 103.273,182.497 101.329,182.108 100.753 C 181.719 100.177,180.904 98.997,180.298 98.131 C 179.693 97.265,178.939 95.576,178.624 94.378 C 178.041 92.159,177.125 90.326,175.023 87.168 C 174.375 86.196,173.619 84.539,173.342 83.486 C 172.800 81.429,171.529 79.567,170.131 78.785 C 169.654 78.517,168.697 77.511,168.006 76.549 C 167.316 75.587,166.594 74.800,166.402 74.800 C 166.210 74.800,164.869 73.633,163.421 72.206 C 160.103 68.936,161.107 69.109,146.550 69.301 C 133.437 69.474,128.581 70.162,126.618 72.124 C 126.248 72.495,125.462 72.904,124.872 73.033 C 124.282 73.163,123.088 73.536,122.219 73.863 C 121.349 74.191,119.028 74.638,117.061 74.858 C 113.514 75.254,109.970 76.350,108.782 77.419 C 107.652 78.436,100.146 80.400,97.388 80.400 C 95.775 80.400,93.167 81.360,91.200 82.679 C 90.430 83.195,89.113 83.804,88.274 84.031 C 85.875 84.681,78.799 90.910,74.400 96.243 L 73.400 97.456 73.455 106.028 C 73.526 117.055,74.527 121.238,77.820 124.263 C 78.919 125.273,80.400 127.902,80.400 128.842 C 80.400 129.202,81.075 130.256,81.900 131.186 C 83.563 133.059,85.497 136.346,86.039 138.216 C 86.233 138.886,87.203 140.207,88.196 141.153 C 89.188 142.098,90.000 143.104,90.000 143.388 C 90.000 144.337,92.129 148.594,92.869 149.123 C 93.271 149.410,93.600 149.831,93.600 150.059 C 93.600 150.286,93.932 150.771,94.337 151.136 C 94.743 151.501,95.598 153.004,96.237 154.475 C 96.877 155.947,97.760 157.351,98.200 157.596 C 98.640 157.841,99.900 159.943,101.000 162.267 C 102.207 164.817,103.327 166.644,103.825 166.876 C 104.278 167.087,105.065 168.101,105.573 169.130 C 107.658 173.348,108.097 174.093,110.006 176.647 C 111.103 178.114,112.000 179.725,112.000 180.227 C 112.000 181.048,113.425 183.163,114.678 184.200 C 115.295 184.711,117.396 188.733,117.720 190.022 C 117.855 190.562,118.603 191.633,119.381 192.402 C 120.160 193.171,121.496 195.258,122.351 197.039 C 123.206 198.820,124.167 200.378,124.487 200.501 C 124.807 200.624,125.953 202.496,127.034 204.662 C 128.114 206.828,129.676 209.299,130.505 210.153 C 131.333 211.007,132.124 212.177,132.262 212.753 C 132.618 214.239,134.291 217.048,136.288 219.5
|
|||
|
" href="/">YannStatic</a></div><!--<button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button>--><!-- <li><button class="button button--secondary button--circle search-button js-search-toggle"><i class="fas fa-search"></i></button></li> -->
|
|||
|
<!-- Champ de recherche -->
|
|||
|
<div id="searchbox" class="search search--dark" style="visibility: visible">
|
|||
|
<div class="main">
|
|||
|
<div class="search__header"></div>
|
|||
|
<div class="search-bar">
|
|||
|
<div class="search-box js-search-box">
|
|||
|
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
|
|||
|
<input id="search-input" type="text" />
|
|||
|
<!-- <div class="search-box__icon-clear js-icon-clear">
|
|||
|
<a><i class="fas fa-times"></i></a>
|
|||
|
</div> -->
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<!-- Script pointing to search-script.js -->
|
|||
|
<script>/*!
|
|||
|
* Simple-Jekyll-Search
|
|||
|
* Copyright 2015-2020, Christian Fei
|
|||
|
* Licensed under the MIT License.
|
|||
|
*/
|
|||
|
|
|||
|
(function(){
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$Templater_7 = {
|
|||
|
compile: compile,
|
|||
|
setOptions: setOptions
|
|||
|
}
|
|||
|
|
|||
|
const options = {}
|
|||
|
options.pattern = /\{(.*?)\}/g
|
|||
|
options.template = ''
|
|||
|
options.middleware = function () {}
|
|||
|
|
|||
|
function setOptions (_options) {
|
|||
|
options.pattern = _options.pattern || options.pattern
|
|||
|
options.template = _options.template || options.template
|
|||
|
if (typeof _options.middleware === 'function') {
|
|||
|
options.middleware = _options.middleware
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function compile (data) {
|
|||
|
return options.template.replace(options.pattern, function (match, prop) {
|
|||
|
const value = options.middleware(prop, data[prop], options.template)
|
|||
|
if (typeof value !== 'undefined') {
|
|||
|
return value
|
|||
|
}
|
|||
|
return data[prop] || match
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
'use strict';
|
|||
|
|
|||
|
function fuzzysearch (needle, haystack) {
|
|||
|
var tlen = haystack.length;
|
|||
|
var qlen = needle.length;
|
|||
|
if (qlen > tlen) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (qlen === tlen) {
|
|||
|
return needle === haystack;
|
|||
|
}
|
|||
|
outer: for (var i = 0, j = 0; i < qlen; i++) {
|
|||
|
var nch = needle.charCodeAt(i);
|
|||
|
while (j < tlen) {
|
|||
|
if (haystack.charCodeAt(j++) === nch) {
|
|||
|
continue outer;
|
|||
|
}
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
var _$fuzzysearch_1 = fuzzysearch;
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
|
|||
|
|
|||
|
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
|
|||
|
|
|||
|
function FuzzySearchStrategy () {
|
|||
|
this.matches = function (string, crit) {
|
|||
|
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
|
|||
|
|
|||
|
function LiteralSearchStrategy () {
|
|||
|
this.matches = function (str, crit) {
|
|||
|
if (!str) return false
|
|||
|
|
|||
|
str = str.trim().toLowerCase()
|
|||
|
crit = crit.trim().toLowerCase()
|
|||
|
|
|||
|
return crit.split(' ').filter(function (word) {
|
|||
|
return str.indexOf(word) >= 0
|
|||
|
}).length === crit.split(' ').length
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$Repository_4 = {
|
|||
|
put: put,
|
|||
|
clear: clear,
|
|||
|
search: search,
|
|||
|
setOptions: __setOptions_4
|
|||
|
}
|
|||
|
|
|||
|
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
|
|||
|
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
|
|||
|
|
|||
|
function NoSort () {
|
|||
|
return 0
|
|||
|
}
|
|||
|
|
|||
|
const data = []
|
|||
|
let opt = {}
|
|||
|
|
|||
|
opt.fuzzy = false
|
|||
|
opt.limit = 10
|
|||
|
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
|
|||
|
opt.sort = NoSort
|
|||
|
opt.exclude = []
|
|||
|
|
|||
|
function put (data) {
|
|||
|
if (isObject(data)) {
|
|||
|
return addObject(data)
|
|||
|
}
|
|||
|
if (isArray(data)) {
|
|||
|
return addArray(data)
|
|||
|
}
|
|||
|
return undefined
|
|||
|
}
|
|||
|
function clear () {
|
|||
|
data.length = 0
|
|||
|
return data
|
|||
|
}
|
|||
|
|
|||
|
function isObject (obj) {
|
|||
|
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
|
|||
|
}
|
|||
|
|
|||
|
function isArray (obj) {
|
|||
|
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
|
|||
|
}
|
|||
|
|
|||
|
function addObject (_data) {
|
|||
|
data.push(_data)
|
|||
|
return data
|
|||
|
}
|
|||
|
|
|||
|
function addArray (_data) {
|
|||
|
const added = []
|
|||
|
clear()
|
|||
|
for (let i = 0, len = _data.length; i < len; i++) {
|
|||
|
if (isObject(_data[i])) {
|
|||
|
added.push(addObject(_data[i]))
|
|||
|
}
|
|||
|
}
|
|||
|
return added
|
|||
|
}
|
|||
|
|
|||
|
function search (crit) {
|
|||
|
if (!crit) {
|
|||
|
return []
|
|||
|
}
|
|||
|
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
|
|||
|
}
|
|||
|
|
|||
|
function __setOptions_4 (_opt) {
|
|||
|
opt = _opt || {}
|
|||
|
|
|||
|
opt.fuzzy = _opt.fuzzy || false
|
|||
|
opt.limit = _opt.limit || 10
|
|||
|
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
|
|||
|
opt.sort = _opt.sort || NoSort
|
|||
|
opt.exclude = _opt.exclude || []
|
|||
|
}
|
|||
|
|
|||
|
function findMatches (data, crit, strategy, opt) {
|
|||
|
const matches = []
|
|||
|
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
|
|||
|
const match = findMatchesInObject(data[i], crit, strategy, opt)
|
|||
|
if (match) {
|
|||
|
matches.push(match)
|
|||
|
}
|
|||
|
}
|
|||
|
return matches
|
|||
|
}
|
|||
|
|
|||
|
function findMatchesInObject (obj, crit, strategy, opt) {
|
|||
|
for (const key in obj) {
|
|||
|
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
|
|||
|
return obj
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function isExcluded (term, excludedTerms) {
|
|||
|
for (let i = 0, len = excludedTerms.length; i < len; i++) {
|
|||
|
const excludedTerm = excludedTerms[i]
|
|||
|
if (new RegExp(excludedTerm).test(term)) {
|
|||
|
return true
|
|||
|
}
|
|||
|
}
|
|||
|
return false
|
|||
|
}
|
|||
|
|
|||
|
/* globals ActiveXObject:false */
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$JSONLoader_2 = {
|
|||
|
load: load
|
|||
|
}
|
|||
|
|
|||
|
function load (location, callback) {
|
|||
|
const xhr = getXHR()
|
|||
|
xhr.open('GET', location, true)
|
|||
|
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
|
|||
|
xhr.send()
|
|||
|
}
|
|||
|
|
|||
|
function createStateChangeListener (xhr, callback) {
|
|||
|
return function () {
|
|||
|
if (xhr.readyState === 4 && xhr.status === 200) {
|
|||
|
try {
|
|||
|
callback(null, JSON.parse(xhr.responseText))
|
|||
|
} catch (err) {
|
|||
|
callback(err, null)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function getXHR () {
|
|||
|
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$OptionsValidator_3 = function OptionsValidator (params) {
|
|||
|
if (!validateParams(params)) {
|
|||
|
throw new Error('-- OptionsValidator: required options missing')
|
|||
|
}
|
|||
|
|
|||
|
if (!(this instanceof OptionsValidator)) {
|
|||
|
return new OptionsValidator(params)
|
|||
|
}
|
|||
|
|
|||
|
const requiredOptions = params.required
|
|||
|
|
|||
|
this.getRequiredOptions = function () {
|
|||
|
return requiredOptions
|
|||
|
}
|
|||
|
|
|||
|
this.validate = function (parameters) {
|
|||
|
const errors = []
|
|||
|
requiredOptions.forEach(function (requiredOptionName) {
|
|||
|
if (typeof parameters[requiredOptionName] === 'undefined') {
|
|||
|
errors.push(requiredOptionName)
|
|||
|
}
|
|||
|
})
|
|||
|
return errors
|
|||
|
}
|
|||
|
|
|||
|
function validateParams (params) {
|
|||
|
if (!params) {
|
|||
|
return false
|
|||
|
}
|
|||
|
return typeof params.required !== 'undefined' && params.required instanceof Array
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$utils_9 = {
|
|||
|
merge: merge,
|
|||
|
isJSON: isJSON
|
|||
|
}
|
|||
|
|
|||
|
function merge (defaultParams, mergeParams) {
|
|||
|
const mergedOptions = {}
|
|||
|
for (const option in defaultParams) {
|
|||
|
mergedOptions[option] = defaultParams[option]
|
|||
|
if (typeof mergeParams[option] !== 'undefined') {
|
|||
|
mergedOptions[option] = mergeParams[option]
|
|||
|
}
|
|||
|
}
|
|||
|
return mergedOptions
|
|||
|
}
|
|||
|
|
|||
|
function isJSON (json) {
|
|||
|
try {
|
|||
|
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
|
|||
|
return true
|
|||
|
}
|
|||
|
return false
|
|||
|
} catch (err) {
|
|||
|
return false
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
var _$src_8 = {};
|
|||
|
(function (window) {
|
|||
|
'use strict'
|
|||
|
|
|||
|
let options = {
|
|||
|
searchInput: null,
|
|||
|
resultsContainer: null,
|
|||
|
json: [],
|
|||
|
success: Function.prototype,
|
|||
|
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
|
|||
|
templateMiddleware: Function.prototype,
|
|||
|
sortMiddleware: function () {
|
|||
|
return 0
|
|||
|
},
|
|||
|
noResultsText: 'No results found',
|
|||
|
limit: 10,
|
|||
|
fuzzy: false,
|
|||
|
debounceTime: null,
|
|||
|
exclude: []
|
|||
|
}
|
|||
|
|
|||
|
let debounceTimerHandle
|
|||
|
const debounce = function (func, delayMillis) {
|
|||
|
if (delayMillis) {
|
|||
|
clearTimeout(debounceTimerHandle)
|
|||
|
debounceTimerHandle = setTimeout(func, delayMillis)
|
|||
|
} else {
|
|||
|
func.call()
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
|
|||
|
|
|||
|
/* removed: const _$Templater_7 = require('./Templater') */;
|
|||
|
/* removed: const _$Repository_4 = require('./Repository') */;
|
|||
|
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
|
|||
|
const optionsValidator = _$OptionsValidator_3({
|
|||
|
required: requiredOptions
|
|||
|
})
|
|||
|
/* removed: const _$utils_9 = require('./utils') */;
|
|||
|
|
|||
|
window.SimpleJekyllSearch = function (_options) {
|
|||
|
const errors = optionsValidator.validate(_options)
|
|||
|
if (errors.length > 0) {
|
|||
|
throwError('You must specify the following required options: ' + requiredOptions)
|
|||
|
}
|
|||
|
|
|||
|
options = _$utils_9.merge(options, _options)
|
|||
|
|
|||
|
_$Templater_7.setOptions({
|
|||
|
template: options.searchResultTemplate,
|
|||
|
middleware: options.templateMiddleware
|
|||
|
})
|
|||
|
|
|||
|
_$Repository_4.setOptions({
|
|||
|
fuzzy: options.fuzzy,
|
|||
|
limit: options.limit,
|
|||
|
sort: options.sortMiddleware,
|
|||
|
exclude: options.exclude
|
|||
|
})
|
|||
|
|
|||
|
if (_$utils_9.isJSON(options.json)) {
|
|||
|
initWithJSON(options.json)
|
|||
|
} else {
|
|||
|
initWithURL(options.json)
|
|||
|
}
|
|||
|
|
|||
|
const rv = {
|
|||
|
search: search
|
|||
|
}
|
|||
|
|
|||
|
typeof options.success === 'function' && options.success.call(rv)
|
|||
|
return rv
|
|||
|
}
|
|||
|
|
|||
|
function initWithJSON (json) {
|
|||
|
_$Repository_4.put(json)
|
|||
|
registerInput()
|
|||
|
}
|
|||
|
|
|||
|
function initWithURL (url) {
|
|||
|
_$JSONLoader_2.load(url, function (err, json) {
|
|||
|
if (err) {
|
|||
|
throwError('failed to get JSON (' + url + ')')
|
|||
|
}
|
|||
|
initWithJSON(json)
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
function emptyResultsContainer () {
|
|||
|
options.resultsContainer.innerHTML = ''
|
|||
|
}
|
|||
|
|
|||
|
function appendToResultsContainer (text) {
|
|||
|
options.resultsContainer.innerHTML += text
|
|||
|
}
|
|||
|
|
|||
|
function registerInput () {
|
|||
|
options.searchInput.addEventListener('input', function (e) {
|
|||
|
if (isWhitelistedKey(e.which)) {
|
|||
|
emptyResultsContainer()
|
|||
|
debounce(function () { search(e.target.value) }, options.debounceTime)
|
|||
|
}
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
function search (query) {
|
|||
|
if (isValidQuery(query)) {
|
|||
|
emptyResultsContainer()
|
|||
|
render(_$Repository_4.search(query), query)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function render (results, query) {
|
|||
|
const len = results.length
|
|||
|
if (len === 0) {
|
|||
|
return appendToResultsContainer(options.noResultsText)
|
|||
|
}
|
|||
|
for (let i = 0; i < len; i++) {
|
|||
|
results[i].query = query
|
|||
|
appendToResultsContainer(_$Templater_7.compile(results[i]))
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function isValidQuery (query) {
|
|||
|
return query && query.length > 0
|
|||
|
}
|
|||
|
|
|||
|
function isWhitelistedKey (key) {
|
|||
|
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
|
|||
|
}
|
|||
|
|
|||
|
function throwError (message) {
|
|||
|
throw new Error('SimpleJekyllSearch --- ' + message)
|
|||
|
}
|
|||
|
})(window)
|
|||
|
|
|||
|
}());
|
|||
|
</script>
|
|||
|
|
|||
|
<!-- Configuration -->
|
|||
|
<script>
|
|||
|
SimpleJekyllSearch({
|
|||
|
searchInput: document.getElementById('search-input'),
|
|||
|
resultsContainer: document.getElementById('results-container'),
|
|||
|
json: '/search.json',
|
|||
|
//searchResultTemplate: '<li><a href="https://static.rnmkcy.eu{url}">{date} {title}</a></li>'
|
|||
|
searchResultTemplate: '<li><a href="{url}">{date} {title}</a></li>'
|
|||
|
})
|
|||
|
</script>
|
|||
|
<!-- Fin déclaration champ de recherche --></div><nav class="navigation">
|
|||
|
<ul><li class="navigation__item"><a href="/archive.html">Etiquettes</a></li><li class="navigation__item"><a href="/htmldoc.html">Documents</a></li><li class="navigation__item"><a href="/liens_ttrss.html">Liens</a></li><li class="navigation__item"><a href="/aide-jekyll-text-theme.html">Aide</a></li></ul>
|
|||
|
</nav></div>
|
|||
|
</header>
|
|||
|
|
|||
|
</div><div class="page__content"><div class ="main"><div class="grid grid--reverse">
|
|||
|
<div class="col-main cell cell--auto"><!-- start custom main top snippet --><div id="results-container" class="search-result js-search-result"></div><!-- end custom main top snippet -->
|
|||
|
<article itemscope itemtype="http://schema.org/Article"><div class="article__header"><header><h1 style="color:Tomato;">Module sans fil nRF24L01+PA-LNA 2.4Ghz et interface avec Arduino</h1></header></div><meta itemprop="headline" content="Module sans fil nRF24L01+PA-LNA 2.4Ghz et interface avec Arduino"><div class="article__info clearfix"><ul class="left-col menu"><li>
|
|||
|
<a class="button button--secondary button--pill button--sm"
|
|||
|
href="/archive.html?tag=arduino">arduino</a>
|
|||
|
</li></ul><ul class="right-col menu"><li>
|
|||
|
<i class="far fa-calendar-alt"></i> <span title="Création" style="color:#FF00FF"> 4 août 2020</span></li></ul></div><meta itemprop="datePublished" content="2020-08-04T00:00:00+02:00">
|
|||
|
<meta itemprop="keywords" content="arduino"><div class="js-article-content">
|
|||
|
<div class="layout--article"><!-- start custom article top snippet -->
|
|||
|
<style>
|
|||
|
#myBtn {
|
|||
|
display: none;
|
|||
|
position: fixed;
|
|||
|
bottom: 10px;
|
|||
|
right: 10px;
|
|||
|
z-index: 99;
|
|||
|
font-size: 12px;
|
|||
|
font-weight: bold;
|
|||
|
border: none;
|
|||
|
outline: none;
|
|||
|
background-color: white;
|
|||
|
color: black;
|
|||
|
cursor: pointer;
|
|||
|
padding: 5px;
|
|||
|
border-radius: 4px;
|
|||
|
}
|
|||
|
|
|||
|
#myBtn:hover {
|
|||
|
background-color: #555;
|
|||
|
}
|
|||
|
</style>
|
|||
|
|
|||
|
<button onclick="topFunction()" id="myBtn" title="Haut de page">⇧</button>
|
|||
|
|
|||
|
<script>
|
|||
|
//Get the button
|
|||
|
var mybutton = document.getElementById("myBtn");
|
|||
|
|
|||
|
// When the user scrolls down 20px from the top of the document, show the button
|
|||
|
window.onscroll = function() {scrollFunction()};
|
|||
|
|
|||
|
function scrollFunction() {
|
|||
|
if (document.body.scrollTop > 20 || document.documentElement.scrollTop > 20) {
|
|||
|
mybutton.style.display = "block";
|
|||
|
} else {
|
|||
|
mybutton.style.display = "none";
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// When the user clicks on the button, scroll to the top of the document
|
|||
|
function topFunction() {
|
|||
|
document.body.scrollTop = 0;
|
|||
|
document.documentElement.scrollTop = 0;
|
|||
|
}
|
|||
|
</script>
|
|||
|
|
|||
|
|
|||
|
<!-- end custom article top snippet -->
|
|||
|
<div class="article__content" itemprop="articleBody"><details>
|
|||
|
<summary><b>Afficher/cacher Sommaire</b></summary>
|
|||
|
<!-- affichage sommaire -->
|
|||
|
<div class="toc-aside js-toc-root"></div>
|
|||
|
</details><h1 id="module-sans-fil-nrf24l01pa-lna">Module sans fil nRF24L01+PA-LNA</h1>
|
|||
|
|
|||
|
<p><img src="/images/nRF24L01-PA-LNA.png" alt="nRF24L01+PA-LNA" /></p>
|
|||
|
|
|||
|
<p>Le fait que deux cartes Arduino ou plus puissent communiquer entre elles sans fil à distance ouvre de nombreuses possibilités, telles que la surveillance à distance des données de capteurs, le contrôle des robots, la domotique, etc. Et lorsqu’il s’agit de solutions RF bidirectionnelles fiables et peu coûteuses, personne ne fait mieux que le module émetteur-récepteur nRF24L01 + de <a href="http://www.nordicsemi.com/">Nordic Semiconductor</a></p>
|
|||
|
|
|||
|
<h2 id="vue-densemble-du-matériel">Vue d’ensemble du matériel</h2>
|
|||
|
|
|||
|
<h3 id="fréquence-radio">Fréquence radio</h3>
|
|||
|
|
|||
|
<p>Le module d’émetteur-récepteur nRF24L01 + est conçu pour fonctionner dans la bande de fréquence ISM mondiale de 2,4 GHz et utilise la modulation GFSK pour la transmission de données. Le taux de transfert de données peut être l’un des 250 kbps, 1 Mbit/s et 2 Mbit/s.</p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p><strong>Quelle est la bande 2,4 GHz ISM?</strong><br />
|
|||
|
La bande de 2,4 GHz est l’une des bandes industrielle, scientifique et médicale (ISM) réservées au niveau international pour l’utilisation d’appareils de faible puissance sans licence. Les exemples sont les téléphones sans fil, les périphériques Bluetooth, les périphériques de communication en champ proche (NFC) et les réseaux informatiques sans fil (WiFi) utilisent tous les fréquences ISM.</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<h3 id="consommation-dénergie">Consommation d’énergie</h3>
|
|||
|
|
|||
|
<p>La tension de fonctionnement du module est comprise entre <strong>1,9 et 3,6 V</strong> , mais la bonne nouvelle est que les <u>broches logiques sont tolérantes à 5 V</u> , ce qui permet de le connecter facilement à un microcontrôleur Arduino ou à tout autre microprocesseur logique sans utiliser de convertisseur de niveau logique.</p>
|
|||
|
|
|||
|
<p>Le module prend en charge la puissance de sortie programmable, à savoir. 0 dBm, -6 dBm, -12 dBm ou -18 dBm et consomme incroyablement environ <strong>12 mA pendant la transmission à 0 dBm</strong>, ce qui est même inférieur à une seule LED. Et surtout, il consomme 26 µA en mode veille et 900 nA en mode veille. C’est pourquoi ils sont le périphérique sans fil de prédilection pour les applications à faible consommation.</p>
|
|||
|
|
|||
|
<h3 id="interface-spi">Interface SPI</h3>
|
|||
|
|
|||
|
<p>Le module émetteur-récepteur nRF24L01 + communique via une interface <strong>SPI</strong> (Serial Peripheral Interface) à 4 broches avec un débit binaire maximal de 10 Mbps . Tous les paramètres tels que le canal de fréquence (125 canaux sélectionnables), la puissance de sortie (0 dBm, -6 dBm, -12 dBm ou -18 dBm) et le débit de données (250kbps, 1Mbps ou 2Mbps) peuvent être configurés via l’interface SPI.</p>
|
|||
|
|
|||
|
<p>Le bus SPI utilise le concept de maître et d’esclave. Dans la plupart des applications, notre Arduino est le maître et le module émetteur-récepteur nRF24L01 + est l’esclave. Contrairement au bus I2C, le nombre d’esclaves sur le bus SPI est limité. Sur l’<u>Arduino Uno, vous pouvez utiliser un maximum de deux esclaves SPI</u>, c’est-à-dire deux modules émetteur-récepteur nRF24L01 +.</p>
|
|||
|
|
|||
|
<p>Spécification du module d’émetteur-récepteur nRF24L01 + :</p>
|
|||
|
|
|||
|
<table>
|
|||
|
<thead>
|
|||
|
<tr>
|
|||
|
<th>nRF24L01 +</th>
|
|||
|
<th>spécification</th>
|
|||
|
</tr>
|
|||
|
</thead>
|
|||
|
<tbody>
|
|||
|
<tr>
|
|||
|
<td>Gamme de fréquences</td>
|
|||
|
<td>Bande ISM de 2,4 GHz</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>Débit de données aérien maximal</td>
|
|||
|
<td>2 Mb/s</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>Format de modulation</td>
|
|||
|
<td>GFSK</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>Max. Puissance de sortie</td>
|
|||
|
<td>0 dBm</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>Tension d’alimentation de fonctionnement</td>
|
|||
|
<td>1,9 V à 3,6 V</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>Max. Courant de fonctionnement</td>
|
|||
|
<td>13,5mA</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>Min. Courant (mode veille)</td>
|
|||
|
<td>26µA</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>Entrées logiques</td>
|
|||
|
<td>5V tolérant</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>Gamme de communication</td>
|
|||
|
<td>800+ m (ligne de mire)</td>
|
|||
|
</tr>
|
|||
|
</tbody>
|
|||
|
</table>
|
|||
|
|
|||
|
<p>Pour plus d’informations sur le nRF24L01 + IC, consultez la <a href="/files/nrf24L01+2.4ghz-transceiver-datasheet.pdf">fiche technique (pdf)</a></p>
|
|||
|
|
|||
|
<h3 id="nrf24l01-module-vs-nrf24l01-palna-module">nRF24L01+ module Vs nRF24L01+ PA/LNA module</h3>
|
|||
|
|
|||
|
<p>Il existe toute une gamme de modules basés sur la puce nRF24L01 +. Voici les versions les plus populaires.</p>
|
|||
|
|
|||
|
<p><img src="/images/nRF24L01-Wireless-Transceiver-Module.png" alt="" /><br />
|
|||
|
<em>Module sans fil nRF24L01 +</em> <br />
|
|||
|
La première version utilise une antenne intégrée. Cela permet une version plus compacte de l’évasion. Cependant, la petite antenne signifie également une plage de transmission inférieure. Avec cette version, vous pourrez communiquer sur une distance de 100 mètres . Bien sûr, c’est à l’extérieur dans un espace ouvert. Votre portée à l’intérieur, surtout à travers les murs, sera légèrement affaiblie.</p>
|
|||
|
|
|||
|
<p><img src="/images/nRF24L01-PA-LNA-External-Antenna-Wireless-Transceiver-Module.png" alt="" /><br />
|
|||
|
<em>Module d’émetteur-récepteur sans fil LNA nRF24L01 + PA avec antenne externe</em><br />
|
|||
|
La deuxième version est livrée avec un connecteur SMA et une antenne canard, mais ce n’est pas la vraie différence. La vraie différence est qu’il est livré avec une puce spéciale RFX2401C qui intègre les circuits de commutation PA, LNA et émission-réception. Cette puce d’extension de portée, associée à une antenne de canard, aide le module à atteindre une portée de transmission considérablement plus grande, de l’ordre de 1000 m.</p>
|
|||
|
|
|||
|
<h3 id="quest-ce-que-pa-lna">Qu’est-ce que PA LNA?</h3>
|
|||
|
|
|||
|
<p>Le PA signifie amplificateur de puissance . Il augmente simplement la puissance du signal transmis par la puce nRF24L01 +. Tandis que LNA signifie <strong>amplificateur à faible bruit</strong> . La fonction de la LNA est de prendre le signal extrêmement faible et incertain de l’antenne (généralement de l’ordre des microvolts ou inférieur à -100 dBm) et l’amplifier à un niveau plus utile (généralement entre 0,5 et 1V)</p>
|
|||
|
|
|||
|
<p><img src="/images/nRF24L01-RF-PA-LNA-Power-Amplifier-Low-Noise-Amplifier-Block-Diagram.png" alt="" /></p>
|
|||
|
|
|||
|
<p>L’amplificateur à faible bruit (LNA) du trajet de réception et l’amplificateur de puissance (PA) du trajet de transmission se connectent à l’antenne via un duplexeur, ce qui sépare les deux signaux et empêche la sortie relativement puissante du PA de surcharger l’entrée sensible du LNA. Pour plus d’informations, consultez cet <a href="https://www.digikey.com/en/articles/techzone/2013/oct/understanding-the-basics-of-low-noise-and-power-amplifiers-in-wireless-designs">article sur digikey.com</a></p>
|
|||
|
|
|||
|
<h2 id="comment-fonctionne-le-module-émetteur-récepteur-nrf24l01-">Comment fonctionne le module émetteur-récepteur nRF24L01 +?</h2>
|
|||
|
|
|||
|
<h3 id="fréquence-du-canal-rf">Fréquence du canal RF</h3>
|
|||
|
|
|||
|
<p>Le module émetteur-récepteur nRF24L01 + transmet et reçoit des données sur une certaine fréquence appelée canal . De plus, pour que deux ou plusieurs modules d’émetteur-récepteur puissent communiquer l’un avec l’autre, ils doivent se trouver sur le même canal. Ce canal peut être n’importe quelle fréquence dans la bande ISM à 2,4 GHz ou, plus précisément, entre 2 200 et 2 525 GHz (2 400 à 2 525 MHz).</p>
|
|||
|
|
|||
|
<p>Chaque canal occupe une largeur de bande inférieure à 1 MHz. Cela nous donne 125 canaux possibles avec un espacement de 1 MHz. Ainsi, le module peut utiliser 125 canaux différents, ce qui permet d’avoir un réseau de 125 modems fonctionnant de manière indépendante à un endroit. <br />
|
|||
|
<img src="/images/nRF24L01-Wireless-Transceiver-2.4GHz-125-RF-Channels-1MHz-Spacing.png" alt="" /></p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>**REMARQUE : ** Le canal occupe une bande passante inférieure à 1 MHz à 250 kbps et à un débit binaire de 1 Mbps. Toutefois, à un débit binaire de 2 Mbits / s, une largeur de bande de 2 MHz est occupée (plus large que la résolution du paramètre de fréquence du canal RF). Ainsi, pour garantir des canaux ne se chevauchant pas et réduire la diaphonie en mode 2 Mbps, <u>vous devez conserver un espacement de 2 MHz entre deux canaux</u>.</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p>La fréquence de canal RF du canal sélectionné est définie selon la formule suivante:</p>
|
|||
|
|
|||
|
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Freq(sélectionné) = 2400 + CH(sélectionné)
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Par exemple, si vous sélectionnez 108 comme canal pour la transmission de données, la fréquence du canal RF de votre canal sera de 2508 MHz → (2400 + 108).</p>
|
|||
|
|
|||
|
<h3 id="nrf24l01--réseau-multicouche">nRF24L01 + réseau multicouche</h3>
|
|||
|
|
|||
|
<p>Le nRF24L01 + fournit une fonctionnalité appelée Multiceiver . C’est une abréviation pour plusieurs émetteurs, récepteur unique. Chaque canal RF est divisé logiquement en 6 canaux de données parallèles appelés canaux de données . En d’autres termes, un canal de données est un canal logique dans le canal RF physique. Chaque canal de données a sa propre adresse physique (adresse de canal de données) et peut être configuré. Ceci peut être illustré comme indiqué ci-dessous. <br />
|
|||
|
<img src="/images/nRF24L01-Wireless-Multiceiver-Network-Multiple-Transmitters-Single-Receiver.png" alt="" /><br />
|
|||
|
Pour simplifier le diagramme ci-dessus, imaginez le récepteur principal agissant en tant que récepteur concentrateur collectant simultanément des informations de 6 nœuds d’émetteurs différents. Le récepteur pivot peut cesser d’écouter à tout moment et fait office d’émetteur. Mais cela ne peut être fait qu’un tuyau/noeud (pipe/node) à la fois.</p>
|
|||
|
|
|||
|
<h3 id="protocole-shockburst-amélioré">Protocole ShockBurst amélioré</h3>
|
|||
|
|
|||
|
<p>Le module émetteur-récepteur nRF24L01 + utilise une structure de paquets appelée Enhanced ShockBurst. Cette structure de paquet simple est décomposée en 5 champs différents, illustrés ci-dessous.<br />
|
|||
|
<img src="/images/nRF24L01-Wireless-Transceiver-Enhanced-ShockBurst-Packet-Structure.png" alt="" /><br />
|
|||
|
La structure d’origine de ShockBurst ne comprenait que les champs Préambule, Adresse, Charge utile et Contrôle de redondance cyclique (CRC). ShockBurst amélioré a apporté une fonctionnalité accrue pour des communications améliorées utilisant un champ de commande de paquets (PCF) récemment introduit.</p>
|
|||
|
|
|||
|
<p>Cette nouvelle structure est excellente pour plusieurs raisons. Premièrement, il autorise les charges utiles de longueur variable avec un spécificateur de longueur de charge utile, ce qui signifie que les charges utiles peuvent varier de 1 à 32 octets.</p>
|
|||
|
|
|||
|
<p>Deuxièmement, il attribue à chaque paquet envoyé un identifiant de paquet, ce qui permet au périphérique récepteur de déterminer si un message est nouveau ou s’il a été retransmis (et peut donc être ignoré).</p>
|
|||
|
|
|||
|
<p>Enfin et surtout, chaque message peut demander l’envoi d’un accusé de réception lorsqu’il est reçu par un autre appareil.</p>
|
|||
|
|
|||
|
<h3 id="nrf24l01--traitement-automatique-des-paquets">nRF24L01 + Traitement automatique des paquets</h3>
|
|||
|
|
|||
|
<p>Passons maintenant à trois scénarios pour mieux comprendre la façon dont deux modules nRF24L01 + se traitent.</p>
|
|||
|
|
|||
|
<p><strong>Transaction avec accusé de réception et interruption</strong>
|
|||
|
Ceci est un exemple de scénario positif. Ici, l’émetteur commence une communication en envoyant un paquet de données au récepteur. Une fois que tout le paquet est transmis, il attend (environ 130 µs) la réception du paquet d’accusé de réception (paquet ACK). Lorsque le destinataire reçoit le paquet, il envoie un paquet ACK à l’émetteur. À la réception du paquet ACK, l’émetteur émet un signal d’interruption (IRQ) pour indiquer que les nouvelles données sont disponibles.<br />
|
|||
|
<img src="/images/nRF24L01-Transceiver-Working-Packet-Transmission.gif" alt="" /></p>
|
|||
|
|
|||
|
<p><strong>Transaction avec perte de paquet de données</strong><br />
|
|||
|
Il s’agit d’un scénario négatif dans lequel une retransmission est nécessaire en raison de la perte du paquet transmis. Une fois le paquet transmis, l’émetteur attend la réception du paquet ACK. Si l’émetteur ne l’obtient pas dans le délai ARD (Auto-Retransmit-Delay), le paquet est retransmis. Lorsque le paquet retransmis est reçu par le récepteur, le paquet ACK est transmis, ce qui génère à son tour une interruption au niveau de l’émetteur.<br />
|
|||
|
<img src="/images/nRF24L01-Transceiver-Working-Packet-Transmission-Data-Lost.gif" alt="" /></p>
|
|||
|
|
|||
|
<p><strong>Transaction avec accusé de réception perdu</strong><br />
|
|||
|
Il s’agit à nouveau d’un scénario négatif dans lequel une retransmission est nécessaire en raison de la perte du paquet ACK. Ici, même si le destinataire reçoit le paquet lors de la première tentative, en raison de la perte du paquet ACK, l’émetteur pense que le destinataire n’a pas du tout reçu le paquet. Ainsi, une fois le délai de retransmission automatique écoulé, il retransmet le paquet. Désormais, lorsque le destinataire reçoit le paquet contenant le même identifiant de paquet que précédemment, il le rejette et envoie à nouveau le paquet ACK.<br />
|
|||
|
<img src="/images/nRF24L01-Transceiver-Working-Packet-Transmission-Acknowledgement-Lost.gif" alt="" /></p>
|
|||
|
|
|||
|
<h2 id="brochage-du-module-démetteur-récepteur-nrf24l01-">Brochage du module d’émetteur-récepteur nRF24L01 +</h2>
|
|||
|
|
|||
|
<p>Examinons le brochage des deux versions du module émetteur-récepteur nRF24L01 +. <br />
|
|||
|
<img src="/images/Pinout-nRF24L01-Wireless-Transceiver-Module.png" alt="" /><br />
|
|||
|
<img src="/images/Pinout-nRF24L01-PA-LNA-External-Antenna-Wireless-Transceiver-Module.png" alt="" /></p>
|
|||
|
|
|||
|
<ul>
|
|||
|
<li><strong><em>GND</em></strong> est la broche de terre. Il est généralement marqué en entourant la broche dans un carré afin de pouvoir être utilisé comme référence pour identifier les autres broches.</li>
|
|||
|
<li><strong><em>VCC</em></strong> alimente le module. Cela peut être n’importe où de 1,9 à 3,9 volts. Vous pouvez le connecter à la sortie 3.3V de votre Arduino. N’oubliez pas que le connecter à une broche 5V détruira probablement votre module nRF24L01 +!</li>
|
|||
|
<li><strong><em>CE</em></strong> (Chip Enable) est une broche active-HIGH. Lorsque sélectionné, le nRF24L01 transmettra ou recevra, selon le mode dans lequel il se trouve actuellement.</li>
|
|||
|
<li><strong><em>CSN</em></strong> (Chip Select Not) est une broche active-LOW et est normalement maintenue à l’état HIGH. Lorsque cette broche devient faible, le nRF24L01 commence à écouter les données sur son port SPI et les traite en conséquence.</li>
|
|||
|
<li><strong><em>SCK</em></strong> (Serial Clock) accepte les impulsions d’horloge fournies par le maître du bus SPI.</li>
|
|||
|
<li><strong><em>MOSI</em></strong> (Master Out Slave In) est l’entrée SPI du nRF24L01.</li>
|
|||
|
<li><strong><em>MISO</em></strong> (Master In Slave Out) est la sortie SPI du nRF24L01.</li>
|
|||
|
<li><strong><em>IRQ</em></strong> est une broche d’interruption pouvant alerter le maître lorsque de nouvelles données sont disponibles pour traitement.</li>
|
|||
|
</ul>
|
|||
|
|
|||
|
<h2 id="arduino--émetteur-récepteur-nrf24l01">Arduino + émetteur-récepteur nRF24L01+</h2>
|
|||
|
|
|||
|
<h3 id="câblage---connexion-du-module-émetteur-récepteur-nrf24l01-à-un-arduino-uno">Câblage - Connexion du module émetteur-récepteur nRF24L01+ à un Arduino UNO</h3>
|
|||
|
|
|||
|
<p>Maintenant que nous comprenons parfaitement le fonctionnement du module émetteur-récepteur nRF24L01 +, nous pouvons commencer à le connecter à notre Arduino!</p>
|
|||
|
|
|||
|
<p>Pour commencer, connectez la broche VCC du module à 3,3 V sur l’Arduino et la broche GND à la terre. Les broches CSN et CE peuvent être connectées à n’importe quelle broche numérique de l’Arduino. Dans notre cas, il est connecté aux broches numériques n ° 8 et n ° 9 respectivement. Nous en sommes maintenant aux broches utilisées pour la communication SPI.</p>
|
|||
|
|
|||
|
<p>Le module émetteur-récepteur nRF24L01 + nécessitant beaucoup de transfert de données, il offrira les meilleures performances lorsqu’il est connecté aux broches SPI matérielles d’un microcontrôleur. Les broches SPI matérielles sont beaucoup plus rapides que le “bit-bang” du code d’interface à l’aide d’un autre ensemble de broches.</p>
|
|||
|
|
|||
|
<p>Notez que chaque carte Arduino a différentes broches SPI qui doivent être connectées en conséquence. Pour les cartes Arduino telles que UNO / Nano V3.0, ces broches sont numériques 13 (SCK), 12 (MISO) et 11 (MOSI).</p>
|
|||
|
|
|||
|
<p>Si vous avez un Mega, les pins sont différents! Vous voudrez utiliser les technologies numériques 50 (MISO), 51 (MOSI), 52 (SCK) et 53 (SS).<br />
|
|||
|
Config. Broches SPI d’Arduino Uno, Arduino Nano et Arduino Mega</p>
|
|||
|
|
|||
|
<table>
|
|||
|
<thead>
|
|||
|
<tr>
|
|||
|
<th>_</th>
|
|||
|
<th>MOSI</th>
|
|||
|
<th>MISO</th>
|
|||
|
<th>SCK</th>
|
|||
|
<th>SS</th>
|
|||
|
</tr>
|
|||
|
</thead>
|
|||
|
<tbody>
|
|||
|
<tr>
|
|||
|
<td>Arduino Uno</td>
|
|||
|
<td>11</td>
|
|||
|
<td>12</td>
|
|||
|
<td>13</td>
|
|||
|
<td>10</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>Arduino Nano</td>
|
|||
|
<td>11</td>
|
|||
|
<td>12</td>
|
|||
|
<td>13</td>
|
|||
|
<td>10</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td>Arduino Mega</td>
|
|||
|
<td>51</td>
|
|||
|
<td>50</td>
|
|||
|
<td>52</td>
|
|||
|
<td>53</td>
|
|||
|
</tr>
|
|||
|
</tbody>
|
|||
|
</table>
|
|||
|
|
|||
|
<p>Si vous utilisez une carte Arduino différente de celle mentionnée ci-dessus, il est conseillé de vérifier la <a href="https://www.arduino.cc/en/Reference/SPI">documentation officielle</a> d’Arduino avant de poursuivre.</p>
|
|||
|
|
|||
|
<p><img src="/images/Arduino-Wiring-Fritzing-Connections-with-nRF24L01-Wireless-Transceiver-Module.png" alt="" /><br />
|
|||
|
<em>Câblage du module émetteur-récepteur sans fil nRF24L01 + sur Arduino UNO</em></p>
|
|||
|
|
|||
|
<p><img src="/images/Arduino-Wiring-Fritzing-Connections-with-nRF24L01-PA-LNA-External-Antenna-Wireless-Module.png" alt="" /><br />
|
|||
|
<em>Câblage du module sans fil nRF24L01 + PA LNA à Arduino UNO</em></p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p>Vous devez faire deux de ces circuits. L’un agit comme émetteur et l’autre comme récepteur. Le câblage pour les deux est identique.</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<h3 id="rf24-bibliothèque-arduino-pour-nrf24l01--module">RF24 Bibliothèque Arduino pour nRF24L01 + Module</h3>
|
|||
|
|
|||
|
<p>L’interfaçage avec le module émetteur-récepteur nRF24L01 + est un travail fastidieux, mais heureusement pour nous, de nombreuses bibliothèques sont disponibles. <a href="http://tmrh20.github.io/RF24/">RF24</a> est l’une des bibliothèques les plus populaires. Cette bibliothèque existe depuis plusieurs années. Il est simple à utiliser pour les débutants, mais offre encore beaucoup pour les utilisateurs avancés. Dans nos expériences, nous utiliserons la même bibliothèque.</p>
|
|||
|
|
|||
|
<p>Vous pouvez télécharger la dernière version de la bibliothèque sur le <a href="https://github.com/nRF24/RF24">fork du référentiel RF24 GitHub</a> ou <a href="https://lastminuteengineers.com/libraries/RF24-master.zip">télécharger le zip</a></p>
|
|||
|
|
|||
|
<p>Pour l’installer, ouvrez l’EDI Arduino, accédez à Esquisse> Inclure la bibliothèque> Ajouter une bibliothèque .ZIP, puis sélectionnez le fichier maître RF24 que vous venez de télécharger. Si vous avez besoin de plus de détails sur l’installation d’une bibliothèque, consultez ce <a href="https://www.arduino.cc/en/Guide/Libraries">tutoriel sur l’installation d’une bibliothèque Arduino</a>.</p>
|
|||
|
|
|||
|
<h3 id="code-arduino---pour-émetteur">Code Arduino - pour émetteur</h3>
|
|||
|
|
|||
|
<p>Dans notre expérience, nous allons simplement envoyer un message traditionnel “ Hello World “ de l’émetteur au récepteur.</p>
|
|||
|
|
|||
|
<p>Voici le schéma que nous allons utiliser pour notre émetteur:</p>
|
|||
|
|
|||
|
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//Include Libraries</span>
|
|||
|
<span class="cp">#include</span> <span class="cpf"><SPI.h></span><span class="cp">
|
|||
|
#include</span> <span class="cpf"><nRF24L01.h></span><span class="cp">
|
|||
|
#include</span> <span class="cpf"><RF24.h></span><span class="cp">
|
|||
|
</span>
|
|||
|
<span class="c1">//create an RF24 object</span>
|
|||
|
<span class="n">RF24</span> <span class="nf">radio</span><span class="p">(</span><span class="mi">9</span><span class="p">,</span> <span class="mi">8</span><span class="p">);</span> <span class="c1">// CE, CSN</span>
|
|||
|
|
|||
|
<span class="c1">//address through which two modules communicate.</span>
|
|||
|
<span class="k">const</span> <span class="n">byte</span> <span class="n">address</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="o">=</span> <span class="s">"00001"</span><span class="p">;</span>
|
|||
|
|
|||
|
<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span>
|
|||
|
<span class="p">{</span>
|
|||
|
<span class="n">radio</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span>
|
|||
|
|
|||
|
<span class="c1">//set the address</span>
|
|||
|
<span class="n">radio</span><span class="p">.</span><span class="n">openWritingPipe</span><span class="p">(</span><span class="n">address</span><span class="p">);</span>
|
|||
|
|
|||
|
<span class="c1">//Set module as transmitter</span>
|
|||
|
<span class="n">radio</span><span class="p">.</span><span class="n">stopListening</span><span class="p">();</span>
|
|||
|
<span class="p">}</span>
|
|||
|
<span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span>
|
|||
|
<span class="p">{</span>
|
|||
|
<span class="c1">//Send message to receiver</span>
|
|||
|
<span class="k">const</span> <span class="kt">char</span> <span class="n">text</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"Hello World"</span><span class="p">;</span>
|
|||
|
<span class="n">radio</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="o">&</span><span class="n">text</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">text</span><span class="p">));</span>
|
|||
|
|
|||
|
<span class="n">delay</span><span class="p">(</span><span class="mi">1000</span><span class="p">);</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>L’esquisse commence par inclure les bibliothèques. La bibliothèque SPI.h gère la communication SPI tandis que nRF24L01.h et RF24.h contrôlent le module.</p>
|
|||
|
|
|||
|
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//Include Libraries</span>
|
|||
|
<span class="cp">#include</span> <span class="cpf"><SPI.h></span><span class="cp">
|
|||
|
#include</span> <span class="cpf"><nRF24L01.h></span><span class="cp">
|
|||
|
#include</span> <span class="cpf"><RF24.h></span><span class="cp">
|
|||
|
</span></code></pre></div></div>
|
|||
|
|
|||
|
<p>Ensuite, nous devons créer un objet RF24. L’objet prend deux numéros de broches en tant que paramètres auxquels les signaux CE et CSN sont connectés.</p>
|
|||
|
|
|||
|
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//create an RF24 object</span>
|
|||
|
<span class="n">RF24</span> <span class="nf">radio</span><span class="p">(</span><span class="mi">9</span><span class="p">,</span> <span class="mi">8</span><span class="p">);</span> <span class="c1">// CE, CSN</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ensuite, nous devons créer un tableau d’octets qui représentera l’adresse du canal par lequel deux modules nRF24L01 + communiquent.</p>
|
|||
|
|
|||
|
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//address through which two modules communicate.</span>
|
|||
|
<span class="k">const</span> <span class="n">byte</span> <span class="n">address</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="o">=</span> <span class="s">"00001"</span><span class="p">;</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Nous pouvons modifier la valeur de cette adresse pour n’importe quelle chaîne de 5 lettres telle que «node1». L’adresse est nécessaire si vous avez quelques modules dans un réseau. Grâce à l’adresse, vous pouvez choisir un module particulier avec lequel vous souhaitez communiquer, de sorte que dans notre cas, nous aurons la même adresse pour l’émetteur et le récepteur.</p>
|
|||
|
|
|||
|
<p>Ensuite, dans la fonction de configuration: nous devons initialiser l’objet radio à l’aide de <code class="language-plaintext highlighter-rouge">radio.begin()</code> et en utilisant la fonction <code class="language-plaintext highlighter-rouge">radio.openWritingPipe()</code> , nous définissons l’adresse de l’émetteur.</p>
|
|||
|
|
|||
|
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//set the address</span>
|
|||
|
<span class="n">radio</span><span class="p">.</span><span class="n">openWritingPipe</span><span class="p">(</span><span class="n">address</span><span class="p">);</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Enfin, nous utiliserons la fonction <code class="language-plaintext highlighter-rouge">radio.stopListening()</code> qui définit le module comme émetteur.</p>
|
|||
|
|
|||
|
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//Set module as transmitter</span>
|
|||
|
<span class="n">radio</span><span class="p">.</span><span class="n">stopListening</span><span class="p">();</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Dans la section de la boucle: nous créons un tableau de caractères auquel nous affectons le message «Hello World». En utilisant la fonction <code class="language-plaintext highlighter-rouge">radio.write()</code> , nous enverrons ce message au destinataire. Le premier argument ici est le message que nous voulons envoyer. Le deuxième argument est le nombre d’octets présents dans ce message.</p>
|
|||
|
|
|||
|
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">const</span> <span class="kt">char</span> <span class="n">text</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"Hello World"</span><span class="p">;</span>
|
|||
|
<span class="n">radio</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="o">&</span><span class="n">text</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">text</span><span class="p">));</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Grâce à cette méthode, vous pouvez envoyer jusqu’à 32 octets à la fois. Parce que c’est la taille maximale d’un seul paquet que nRF24L01 + peut gérer. Si vous avez besoin d’une confirmation que le destinataire a reçu des données, la méthode <code class="language-plaintext highlighter-rouge">radio.write()</code> renvoie une valeur <code class="language-plaintext highlighter-rouge">bool</code> . S’il renvoie TRUE, les données sont parvenues au destinataire. S’il renvoie FALSE, les données ont été perdues.</p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p><strong>REMARQUE :</strong> la fonction <code class="language-plaintext highlighter-rouge">radio.write()</code> bloque le programme jusqu’à ce qu’il reçoive l’accusé de réception ou qu’il n’y ait plus aucune tentative de retransmission.</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<h3 id="code-arduino---pour-le-récepteur">Code Arduino - Pour le récepteur</h3>
|
|||
|
|
|||
|
<p>Voici le croquis que nous allons utiliser pour notre récepteur</p>
|
|||
|
|
|||
|
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//Include Libraries</span>
|
|||
|
<span class="cp">#include</span> <span class="cpf"><SPI.h></span><span class="cp">
|
|||
|
#include</span> <span class="cpf"><nRF24L01.h></span><span class="cp">
|
|||
|
#include</span> <span class="cpf"><RF24.h></span><span class="cp">
|
|||
|
</span>
|
|||
|
<span class="c1">//create an RF24 object</span>
|
|||
|
<span class="n">RF24</span> <span class="nf">radio</span><span class="p">(</span><span class="mi">9</span><span class="p">,</span> <span class="mi">8</span><span class="p">);</span> <span class="c1">// CE, CSN</span>
|
|||
|
|
|||
|
<span class="c1">//address through which two modules communicate.</span>
|
|||
|
<span class="k">const</span> <span class="n">byte</span> <span class="n">address</span><span class="p">[</span><span class="mi">6</span><span class="p">]</span> <span class="o">=</span> <span class="s">"00001"</span><span class="p">;</span>
|
|||
|
|
|||
|
<span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span>
|
|||
|
<span class="p">{</span>
|
|||
|
<span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">Serial</span><span class="p">);</span>
|
|||
|
<span class="n">Serial</span><span class="p">.</span><span class="n">begin</span><span class="p">(</span><span class="mi">9600</span><span class="p">);</span>
|
|||
|
|
|||
|
<span class="n">radio</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span>
|
|||
|
|
|||
|
<span class="c1">//set the address</span>
|
|||
|
<span class="n">radio</span><span class="p">.</span><span class="n">openReadingPipe</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">address</span><span class="p">);</span>
|
|||
|
|
|||
|
<span class="c1">//Set module as receiver</span>
|
|||
|
<span class="n">radio</span><span class="p">.</span><span class="n">startListening</span><span class="p">();</span>
|
|||
|
<span class="p">}</span>
|
|||
|
|
|||
|
<span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span>
|
|||
|
<span class="p">{</span>
|
|||
|
<span class="c1">//Read the data if available in buffer</span>
|
|||
|
<span class="k">if</span> <span class="p">(</span><span class="n">radio</span><span class="p">.</span><span class="n">available</span><span class="p">())</span>
|
|||
|
<span class="p">{</span>
|
|||
|
<span class="kt">char</span> <span class="n">text</span><span class="p">[</span><span class="mi">32</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">};</span>
|
|||
|
<span class="n">radio</span><span class="p">.</span><span class="n">read</span><span class="p">(</span><span class="o">&</span><span class="n">text</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">text</span><span class="p">));</span>
|
|||
|
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="n">text</span><span class="p">);</span>
|
|||
|
<span class="p">}</span>
|
|||
|
<span class="p">}</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Ce programme ressemble beaucoup au programme de l’émetteur, à l’exception de quelques modifications.</p>
|
|||
|
|
|||
|
<p>Au début de la fonction de configuration, nous commençons la communication série. Ensuite, en utilisant la fonction <code class="language-plaintext highlighter-rouge">radio.setReadingPipe()</code> , nous définissons la même adresse que celle de l’émetteur, ce qui permet la communication entre l’émetteur et le récepteur.</p>
|
|||
|
|
|||
|
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="c1">//set the address</span>
|
|||
|
<span class="n">radio</span><span class="p">.</span><span class="n">openReadingPipe</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">address</span><span class="p">);</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Le premier argument est le numéro du flux. Vous pouvez créer jusqu’à 6 flux qui répondent à différentes adresses. Nous avons créé uniquement l’adresse pour le numéro de flux 0. Le deuxième argument est l’adresse à laquelle le flux réagira pour collecter les données.</p>
|
|||
|
|
|||
|
<p>L’étape suivante consiste à définir le module en tant que récepteur et à commencer à recevoir des données. Pour ce faire, nous utilisons la fonction <code class="language-plaintext highlighter-rouge">radio.startListening()</code>. À partir de ce moment, le modem attend les données envoyées à l’adresse spécifiée.</p>
|
|||
|
|
|||
|
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">//Set module as receiver</span>
|
|||
|
<span class="n">radio</span><span class="p">.</span><span class="n">startListening</span><span class="p">();</span>
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Dans la fonction de boucle: L’esquisse vérifie si des données sont arrivées à l’adresse à l’aide de la méthode <code class="language-plaintext highlighter-rouge">radio.available()</code> . Cette méthode renvoie la valeur TRUE si des données sont disponibles dans la mémoire tampon.</p>
|
|||
|
|
|||
|
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="n">radio</span><span class="p">.</span><span class="n">available</span><span class="p">())</span>
|
|||
|
<span class="p">{</span>
|
|||
|
<span class="kt">char</span> <span class="n">text</span><span class="p">[</span><span class="mi">32</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">};</span>
|
|||
|
<span class="n">radio</span><span class="p">.</span><span class="n">read</span><span class="p">(</span><span class="o">&</span><span class="n">text</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">text</span><span class="p">));</span>
|
|||
|
<span class="n">Serial</span><span class="p">.</span><span class="n">println</span><span class="p">(</span><span class="n">text</span><span class="p">);</span>
|
|||
|
<span class="p">}</span>
|
|||
|
|
|||
|
</code></pre></div></div>
|
|||
|
|
|||
|
<p>Si les données sont reçues, un tableau de 32 caractères rempli de zéros est créé (plus tard, le programme le remplira avec les données reçues). Pour lire les données, nous utilisons la méthode <code class="language-plaintext highlighter-rouge">radio.read (& text, sizeof (text))</code> . Cela va stocker les données reçues dans notre tableau de caractères.</p>
|
|||
|
|
|||
|
<p>À la fin, nous imprimons simplement le message reçu sur le moniteur série. Si vous avez tout fait correctement et qu’il n’y a pas d’erreur dans les connexions, vous devriez voir quelque chose comme ceci dans votre moniteur série. <br />
|
|||
|
<img src="/images/nRF24L01-Transceiver-RF24-Library-Sketch-Output-on-Serial-Monitor.png" alt="" /><br />
|
|||
|
<em>nRF24L01 + sortie de l’émetteur-récepteur sur le moniteur série</em></p>
|
|||
|
|
|||
|
<h2 id="amélioration-de-la-portée-du-module-émetteur-récepteur-nrf24l01-">Amélioration de la portée du module émetteur-récepteur nRF24L01 +</h2>
|
|||
|
|
|||
|
<p>Un paramètre clé pour un système de communication sans fil est la plage de communication. Dans de nombreux cas, c’est le facteur décisif pour choisir une solution RF. Discutons donc de ce que nous pouvons faire pour améliorer la portée de notre module.</p>
|
|||
|
|
|||
|
<h3 id="réduire-le-bruit-dalimentation">Réduire le bruit d’alimentation</h3>
|
|||
|
|
|||
|
<p>Un circuit RF qui génère un signal RF est très sensible au bruit de l’alimentation. S’il n’est pas contrôlé, le bruit de l’alimentation peut réduire considérablement la portée que vous pouvez obtenir.</p>
|
|||
|
|
|||
|
<p>À moins que la source d’alimentation ne soit une batterie autonome, il y a de fortes chances pour qu’il y ait du bruit associé à la génération de l’énergie. Pour éviter que ce bruit ne pénètre dans le système, il est conseillé de placer un condensateur de filtrage de 10 µf sur la ligne d’ alimentation , aussi près que possible du module nRF24L01 +.</p>
|
|||
|
|
|||
|
<p>Pour vous en sortir le plus facilement, utilisez un module d’adaptateur très économique pour nRF24L01.<br />
|
|||
|
<img src="/images/nRF24L01-5V-Power-Adapter.png" alt="" /><br />
|
|||
|
<em>nRF24L01 + adaptateur</em><br />
|
|||
|
Le module adaptateur dispose d’un connecteur femelle à 8 broches pour vous permettre de brancher votre module nRF24L01. Il peut accueillir à la fois le module dont nous avons parlé précédemment, celui avec antenne intégrée et l’autre avec antenne externe (PA / LNA). Il possède également un connecteur mâle à 6 broches pour les connexions SPI et Interrupt et un connecteur à 2 broches pour l’alimentation.</p>
|
|||
|
|
|||
|
<p>Le module adaptateur possède son propre régulateur de tension de 3,3 volts et un ensemble de condensateurs de filtrage, ce qui vous permet de l’alimenter avec une alimentation de 5 volts.</p>
|
|||
|
|
|||
|
<h3 id="changer-la-fréquence-de-votre-canal">Changer la fréquence de votre canal</h3>
|
|||
|
|
|||
|
<p>L’environnement extérieur est une autre source potentielle de bruit pour un circuit RF, en particulier si vous avez des réseaux voisins fixés sur le même canal ou des interférences provenant d’autres composants électroniques.</p>
|
|||
|
|
|||
|
<p>Pour éviter que ces signaux ne causent des problèmes, nous vous suggérons d’<u>**utiliser les 25 canaux les plus élevés de votre module nRF24L01 +**</u>. La raison en est que le WiFi utilise la plupart des canaux inférieurs.</p>
|
|||
|
|
|||
|
<h3 id="taux-de-données-inférieur">Taux de données inférieur</h3>
|
|||
|
|
|||
|
<p>Le nRF24L01 + offre la plus haute sensibilité de récepteur à une vitesse de 250 Kbits/s, soit -94dBm. Cependant, à un débit de 2 Mbits/s, la sensibilité du récepteur chute à -82dBm. Si vous parlez cette langue, vous savez que le récepteur à 250 Kbps est près de 10 fois plus sensible que celui à 2 Mbps.<br />
|
|||
|
Cela signifie que le récepteur peut décoder un signal 10 fois plus faible.</p>
|
|||
|
|
|||
|
<blockquote>
|
|||
|
<p><strong>Que signifie sensibilité du récepteur (Rx)?</strong><br />
|
|||
|
La sensibilité du récepteur est le niveau de puissance le plus bas auquel le récepteur peut détecter un signal RF. Plus la valeur absolue du nombre négatif est grande, meilleure est la sensibilité du récepteur. Par exemple, une sensibilité du récepteur de -94 dBm est préférable à une sensibilité du récepteur de -82 dBm sur 12 dB.</p>
|
|||
|
</blockquote>
|
|||
|
|
|||
|
<p>Donc, réduire le débit de données peut considérablement améliorer la portée que vous pouvez atteindre. En outre, pour la plupart de nos projets, une vitesse de 250 Kbps est plus que suffisante.</p>
|
|||
|
|
|||
|
<h3 id="puissance-de-sortie-supérieure">Puissance de sortie supérieure</h3>
|
|||
|
|
|||
|
<p>Le réglage de la puissance de sortie maximale peut également améliorer la portée de communication. Le nRF24L01 + vous permet de choisir l’une des valeurs de puissance de sortie. 0 dBm, -6 dBm, -12 dBm ou -18 dBm. La sélection d’ une puissance de sortie de 0 dBm envoie un signal plus fort dans les airs.</p>
|
|||
|
|
|||
|
|
|||
|
</div>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<div class="d-print-none"><footer class="article__footer"><meta itemprop="dateModified" content="2020-08-04T00:00:00+02:00"><!-- start custom article footer snippet -->
|
|||
|
|
|||
|
<!-- end custom article footer snippet -->
|
|||
|
<!--
|
|||
|
<div align="right"><a type="application/rss+xml" href="/feed.xml" title="S'abonner"><i class="fa fa-rss fa-2x"></i></a>
|
|||
|
|
|||
|
 </div>
|
|||
|
-->
|
|||
|
</footer>
|
|||
|
<div class="article__section-navigator clearfix"><div class="previous"><span>PRÉCÉDENT</span><a href="/2020/08/03/syntaxe-markdown.html">Syntaxe markdown</a></div><div class="next"><span>SUIVANT</span><a href="/2020/08/04/Systemd_Path_Unit_pour_surveiller_les_fichiers_et_les_repertoire.html">Systemd Path Unit pour surveiller les fichiers et les répertoires</a></div></div></div>
|
|||
|
|
|||
|
</div>
|
|||
|
|
|||
|
<script>(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
$(function() {
|
|||
|
var $this ,$scroll;
|
|||
|
var $articleContent = $('.js-article-content');
|
|||
|
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
|
|||
|
var scroll = hasSidebar ? '.js-page-main' : 'html, body';
|
|||
|
$scroll = $(scroll);
|
|||
|
|
|||
|
$articleContent.find('.highlight').each(function() {
|
|||
|
$this = $(this);
|
|||
|
$this.attr('data-lang', $this.find('code').attr('data-lang'));
|
|||
|
});
|
|||
|
$articleContent.find('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]').each(function() {
|
|||
|
$this = $(this);
|
|||
|
$this.append($('<a class="anchor d-print-none" aria-hidden="true"></a>').html('<i class="fas fa-anchor"></i>'));
|
|||
|
});
|
|||
|
$articleContent.on('click', '.anchor', function() {
|
|||
|
$scroll.scrollToAnchor('#' + $(this).parent().attr('id'), 400);
|
|||
|
});
|
|||
|
});
|
|||
|
});
|
|||
|
})();
|
|||
|
</script>
|
|||
|
|
|||
|
</div><section class="page__comments d-print-none"></section></article><!-- start custom main bottom snippet -->
|
|||
|
<!-- end custom main bottom snippet -->
|
|||
|
</div>
|
|||
|
</div></div></div></div>
|
|||
|
</div><script>(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
var $body = $('body'), $window = $(window);
|
|||
|
var $pageRoot = $('.js-page-root'), $pageMain = $('.js-page-main');
|
|||
|
var activeCount = 0;
|
|||
|
function modal(options) {
|
|||
|
var $root = this, visible, onChange, hideWhenWindowScroll = false;
|
|||
|
var scrollTop;
|
|||
|
function setOptions(options) {
|
|||
|
var _options = options || {};
|
|||
|
visible = _options.initialVisible === undefined ? false : show;
|
|||
|
onChange = _options.onChange;
|
|||
|
hideWhenWindowScroll = _options.hideWhenWindowScroll;
|
|||
|
}
|
|||
|
function init() {
|
|||
|
setState(visible);
|
|||
|
}
|
|||
|
function setState(isShow) {
|
|||
|
if (isShow === visible) {
|
|||
|
return;
|
|||
|
}
|
|||
|
visible = isShow;
|
|||
|
if (visible) {
|
|||
|
activeCount++;
|
|||
|
scrollTop = $(window).scrollTop() || $pageMain.scrollTop();
|
|||
|
$root.addClass('modal--show');
|
|||
|
$pageMain.scrollTop(scrollTop);
|
|||
|
activeCount === 1 && ($pageRoot.addClass('show-modal'), $body.addClass('of-hidden'));
|
|||
|
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.on('scroll', hide);
|
|||
|
$window.on('keyup', handleKeyup);
|
|||
|
} else {
|
|||
|
activeCount > 0 && activeCount--;
|
|||
|
$root.removeClass('modal--show');
|
|||
|
$window.scrollTop(scrollTop);
|
|||
|
activeCount === 0 && ($pageRoot.removeClass('show-modal'), $body.removeClass('of-hidden'));
|
|||
|
hideWhenWindowScroll && window.hasEvent('touchstart') && $window.off('scroll', hide);
|
|||
|
$window.off('keyup', handleKeyup);
|
|||
|
}
|
|||
|
onChange && onChange(visible);
|
|||
|
}
|
|||
|
function show() {
|
|||
|
setState(true);
|
|||
|
}
|
|||
|
function hide() {
|
|||
|
setState(false);
|
|||
|
}
|
|||
|
function handleKeyup(e) {
|
|||
|
// Char Code: 27 ESC
|
|||
|
if (e.which === 27) {
|
|||
|
hide();
|
|||
|
}
|
|||
|
}
|
|||
|
setOptions(options);
|
|||
|
init();
|
|||
|
return {
|
|||
|
show: show,
|
|||
|
hide: hide,
|
|||
|
$el: $root
|
|||
|
};
|
|||
|
}
|
|||
|
$.fn.modal = modal;
|
|||
|
});
|
|||
|
})();
|
|||
|
</script><div class="modal modal--overflow page__search-modal d-print-none js-page-search-modal"><script>
|
|||
|
(function () {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
// search panel
|
|||
|
var search = (window.search || (window.search = {}));
|
|||
|
var useDefaultSearchBox = window.useDefaultSearchBox === undefined ?
|
|||
|
true : window.useDefaultSearchBox ;
|
|||
|
|
|||
|
var $searchModal = $('.js-page-search-modal');
|
|||
|
var $searchToggle = $('.js-search-toggle');
|
|||
|
var searchModal = $searchModal.modal({ onChange: handleModalChange, hideWhenWindowScroll: true });
|
|||
|
var modalVisible = false;
|
|||
|
search.searchModal = searchModal;
|
|||
|
|
|||
|
var $searchBox = null;
|
|||
|
var $searchInput = null;
|
|||
|
var $searchClear = null;
|
|||
|
|
|||
|
function getModalVisible() {
|
|||
|
return modalVisible;
|
|||
|
}
|
|||
|
search.getModalVisible = getModalVisible;
|
|||
|
|
|||
|
function handleModalChange(visible) {
|
|||
|
modalVisible = visible;
|
|||
|
if (visible) {
|
|||
|
search.onShow && search.onShow();
|
|||
|
useDefaultSearchBox && $searchInput[0] && $searchInput[0].focus();
|
|||
|
} else {
|
|||
|
search.onShow && search.onHide();
|
|||
|
useDefaultSearchBox && $searchInput[0] && $searchInput[0].blur();
|
|||
|
setTimeout(function() {
|
|||
|
useDefaultSearchBox && ($searchInput.val(''), $searchBox.removeClass('not-empty'));
|
|||
|
search.clear && search.clear();
|
|||
|
window.pageAsideAffix && window.pageAsideAffix.refresh();
|
|||
|
}, 400);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
$searchToggle.on('click', function() {
|
|||
|
modalVisible ? searchModal.hide() : searchModal.show();
|
|||
|
});
|
|||
|
// Char Code: 83 S, 191 /
|
|||
|
$(window).on('keyup', function(e) {
|
|||
|
if (!modalVisible && !window.isFormElement(e.target || e.srcElement) && (e.which === 83 || e.which === 191)) {
|
|||
|
modalVisible || searchModal.show();
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
if (useDefaultSearchBox) {
|
|||
|
$searchBox = $('.js-search-box');
|
|||
|
$searchInput = $searchBox.children('input');
|
|||
|
$searchClear = $searchBox.children('.js-icon-clear');
|
|||
|
search.getSearchInput = function() {
|
|||
|
return $searchInput.get(0);
|
|||
|
};
|
|||
|
search.getVal = function() {
|
|||
|
return $searchInput.val();
|
|||
|
};
|
|||
|
search.setVal = function(val) {
|
|||
|
$searchInput.val(val);
|
|||
|
};
|
|||
|
|
|||
|
$searchInput.on('focus', function() {
|
|||
|
$(this).addClass('focus');
|
|||
|
});
|
|||
|
$searchInput.on('blur', function() {
|
|||
|
$(this).removeClass('focus');
|
|||
|
});
|
|||
|
$searchInput.on('input', window.throttle(function() {
|
|||
|
var val = $(this).val();
|
|||
|
if (val === '' || typeof val !== 'string') {
|
|||
|
search.clear && search.clear();
|
|||
|
} else {
|
|||
|
$searchBox.addClass('not-empty');
|
|||
|
search.onInputNotEmpty && search.onInputNotEmpty(val);
|
|||
|
}
|
|||
|
}, 400));
|
|||
|
$searchClear.on('click', function() {
|
|||
|
$searchInput.val(''); $searchBox.removeClass('not-empty');
|
|||
|
search.clear && search.clear();
|
|||
|
});
|
|||
|
}
|
|||
|
});
|
|||
|
})();
|
|||
|
</script><div class="search search--dark">
|
|||
|
<div class="main">
|
|||
|
<div class="search__header">Recherche</div>
|
|||
|
<div class="search-bar">
|
|||
|
<div class="search-box js-search-box">
|
|||
|
<div class="search-box__icon-search"><i class="fas fa-search"></i></div>
|
|||
|
<input id="search-input" type="text" />
|
|||
|
<div class="search-box__icon-clear js-icon-clear">
|
|||
|
<a><i class="fas fa-times"></i></a>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<button class="button button--theme-dark button--pill search__cancel js-search-toggle">
|
|||
|
Annuler</button>
|
|||
|
</div>
|
|||
|
<div id="results-container" class="search-result js-search-result"></div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
<!-- Script pointing to search-script.js -->
|
|||
|
<script>/*!
|
|||
|
* Simple-Jekyll-Search
|
|||
|
* Copyright 2015-2020, Christian Fei
|
|||
|
* Licensed under the MIT License.
|
|||
|
*/
|
|||
|
|
|||
|
(function(){
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$Templater_7 = {
|
|||
|
compile: compile,
|
|||
|
setOptions: setOptions
|
|||
|
}
|
|||
|
|
|||
|
const options = {}
|
|||
|
options.pattern = /\{(.*?)\}/g
|
|||
|
options.template = ''
|
|||
|
options.middleware = function () {}
|
|||
|
|
|||
|
function setOptions (_options) {
|
|||
|
options.pattern = _options.pattern || options.pattern
|
|||
|
options.template = _options.template || options.template
|
|||
|
if (typeof _options.middleware === 'function') {
|
|||
|
options.middleware = _options.middleware
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function compile (data) {
|
|||
|
return options.template.replace(options.pattern, function (match, prop) {
|
|||
|
const value = options.middleware(prop, data[prop], options.template)
|
|||
|
if (typeof value !== 'undefined') {
|
|||
|
return value
|
|||
|
}
|
|||
|
return data[prop] || match
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
'use strict';
|
|||
|
|
|||
|
function fuzzysearch (needle, haystack) {
|
|||
|
var tlen = haystack.length;
|
|||
|
var qlen = needle.length;
|
|||
|
if (qlen > tlen) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
if (qlen === tlen) {
|
|||
|
return needle === haystack;
|
|||
|
}
|
|||
|
outer: for (var i = 0, j = 0; i < qlen; i++) {
|
|||
|
var nch = needle.charCodeAt(i);
|
|||
|
while (j < tlen) {
|
|||
|
if (haystack.charCodeAt(j++) === nch) {
|
|||
|
continue outer;
|
|||
|
}
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
var _$fuzzysearch_1 = fuzzysearch;
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
/* removed: const _$fuzzysearch_1 = require('fuzzysearch') */;
|
|||
|
|
|||
|
var _$FuzzySearchStrategy_5 = new FuzzySearchStrategy()
|
|||
|
|
|||
|
function FuzzySearchStrategy () {
|
|||
|
this.matches = function (string, crit) {
|
|||
|
return _$fuzzysearch_1(crit.toLowerCase(), string.toLowerCase())
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$LiteralSearchStrategy_6 = new LiteralSearchStrategy()
|
|||
|
|
|||
|
function LiteralSearchStrategy () {
|
|||
|
this.matches = function (str, crit) {
|
|||
|
if (!str) return false
|
|||
|
|
|||
|
str = str.trim().toLowerCase()
|
|||
|
crit = crit.trim().toLowerCase()
|
|||
|
|
|||
|
return crit.split(' ').filter(function (word) {
|
|||
|
return str.indexOf(word) >= 0
|
|||
|
}).length === crit.split(' ').length
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$Repository_4 = {
|
|||
|
put: put,
|
|||
|
clear: clear,
|
|||
|
search: search,
|
|||
|
setOptions: __setOptions_4
|
|||
|
}
|
|||
|
|
|||
|
/* removed: const _$FuzzySearchStrategy_5 = require('./SearchStrategies/FuzzySearchStrategy') */;
|
|||
|
/* removed: const _$LiteralSearchStrategy_6 = require('./SearchStrategies/LiteralSearchStrategy') */;
|
|||
|
|
|||
|
function NoSort () {
|
|||
|
return 0
|
|||
|
}
|
|||
|
|
|||
|
const data = []
|
|||
|
let opt = {}
|
|||
|
|
|||
|
opt.fuzzy = false
|
|||
|
opt.limit = 10
|
|||
|
opt.searchStrategy = opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
|
|||
|
opt.sort = NoSort
|
|||
|
opt.exclude = []
|
|||
|
|
|||
|
function put (data) {
|
|||
|
if (isObject(data)) {
|
|||
|
return addObject(data)
|
|||
|
}
|
|||
|
if (isArray(data)) {
|
|||
|
return addArray(data)
|
|||
|
}
|
|||
|
return undefined
|
|||
|
}
|
|||
|
function clear () {
|
|||
|
data.length = 0
|
|||
|
return data
|
|||
|
}
|
|||
|
|
|||
|
function isObject (obj) {
|
|||
|
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Object]'
|
|||
|
}
|
|||
|
|
|||
|
function isArray (obj) {
|
|||
|
return Boolean(obj) && Object.prototype.toString.call(obj) === '[object Array]'
|
|||
|
}
|
|||
|
|
|||
|
function addObject (_data) {
|
|||
|
data.push(_data)
|
|||
|
return data
|
|||
|
}
|
|||
|
|
|||
|
function addArray (_data) {
|
|||
|
const added = []
|
|||
|
clear()
|
|||
|
for (let i = 0, len = _data.length; i < len; i++) {
|
|||
|
if (isObject(_data[i])) {
|
|||
|
added.push(addObject(_data[i]))
|
|||
|
}
|
|||
|
}
|
|||
|
return added
|
|||
|
}
|
|||
|
|
|||
|
function search (crit) {
|
|||
|
if (!crit) {
|
|||
|
return []
|
|||
|
}
|
|||
|
return findMatches(data, crit, opt.searchStrategy, opt).sort(opt.sort)
|
|||
|
}
|
|||
|
|
|||
|
function __setOptions_4 (_opt) {
|
|||
|
opt = _opt || {}
|
|||
|
|
|||
|
opt.fuzzy = _opt.fuzzy || false
|
|||
|
opt.limit = _opt.limit || 10
|
|||
|
opt.searchStrategy = _opt.fuzzy ? _$FuzzySearchStrategy_5 : _$LiteralSearchStrategy_6
|
|||
|
opt.sort = _opt.sort || NoSort
|
|||
|
opt.exclude = _opt.exclude || []
|
|||
|
}
|
|||
|
|
|||
|
function findMatches (data, crit, strategy, opt) {
|
|||
|
const matches = []
|
|||
|
for (let i = 0; i < data.length && matches.length < opt.limit; i++) {
|
|||
|
const match = findMatchesInObject(data[i], crit, strategy, opt)
|
|||
|
if (match) {
|
|||
|
matches.push(match)
|
|||
|
}
|
|||
|
}
|
|||
|
return matches
|
|||
|
}
|
|||
|
|
|||
|
function findMatchesInObject (obj, crit, strategy, opt) {
|
|||
|
for (const key in obj) {
|
|||
|
if (!isExcluded(obj[key], opt.exclude) && strategy.matches(obj[key], crit)) {
|
|||
|
return obj
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function isExcluded (term, excludedTerms) {
|
|||
|
for (let i = 0, len = excludedTerms.length; i < len; i++) {
|
|||
|
const excludedTerm = excludedTerms[i]
|
|||
|
if (new RegExp(excludedTerm).test(term)) {
|
|||
|
return true
|
|||
|
}
|
|||
|
}
|
|||
|
return false
|
|||
|
}
|
|||
|
|
|||
|
/* globals ActiveXObject:false */
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$JSONLoader_2 = {
|
|||
|
load: load
|
|||
|
}
|
|||
|
|
|||
|
function load (location, callback) {
|
|||
|
const xhr = getXHR()
|
|||
|
xhr.open('GET', location, true)
|
|||
|
xhr.onreadystatechange = createStateChangeListener(xhr, callback)
|
|||
|
xhr.send()
|
|||
|
}
|
|||
|
|
|||
|
function createStateChangeListener (xhr, callback) {
|
|||
|
return function () {
|
|||
|
if (xhr.readyState === 4 && xhr.status === 200) {
|
|||
|
try {
|
|||
|
callback(null, JSON.parse(xhr.responseText))
|
|||
|
} catch (err) {
|
|||
|
callback(err, null)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function getXHR () {
|
|||
|
return window.XMLHttpRequest ? new window.XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP')
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$OptionsValidator_3 = function OptionsValidator (params) {
|
|||
|
if (!validateParams(params)) {
|
|||
|
throw new Error('-- OptionsValidator: required options missing')
|
|||
|
}
|
|||
|
|
|||
|
if (!(this instanceof OptionsValidator)) {
|
|||
|
return new OptionsValidator(params)
|
|||
|
}
|
|||
|
|
|||
|
const requiredOptions = params.required
|
|||
|
|
|||
|
this.getRequiredOptions = function () {
|
|||
|
return requiredOptions
|
|||
|
}
|
|||
|
|
|||
|
this.validate = function (parameters) {
|
|||
|
const errors = []
|
|||
|
requiredOptions.forEach(function (requiredOptionName) {
|
|||
|
if (typeof parameters[requiredOptionName] === 'undefined') {
|
|||
|
errors.push(requiredOptionName)
|
|||
|
}
|
|||
|
})
|
|||
|
return errors
|
|||
|
}
|
|||
|
|
|||
|
function validateParams (params) {
|
|||
|
if (!params) {
|
|||
|
return false
|
|||
|
}
|
|||
|
return typeof params.required !== 'undefined' && params.required instanceof Array
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
'use strict'
|
|||
|
|
|||
|
var _$utils_9 = {
|
|||
|
merge: merge,
|
|||
|
isJSON: isJSON
|
|||
|
}
|
|||
|
|
|||
|
function merge (defaultParams, mergeParams) {
|
|||
|
const mergedOptions = {}
|
|||
|
for (const option in defaultParams) {
|
|||
|
mergedOptions[option] = defaultParams[option]
|
|||
|
if (typeof mergeParams[option] !== 'undefined') {
|
|||
|
mergedOptions[option] = mergeParams[option]
|
|||
|
}
|
|||
|
}
|
|||
|
return mergedOptions
|
|||
|
}
|
|||
|
|
|||
|
function isJSON (json) {
|
|||
|
try {
|
|||
|
if (json instanceof Object && JSON.parse(JSON.stringify(json))) {
|
|||
|
return true
|
|||
|
}
|
|||
|
return false
|
|||
|
} catch (err) {
|
|||
|
return false
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
var _$src_8 = {};
|
|||
|
(function (window) {
|
|||
|
'use strict'
|
|||
|
|
|||
|
let options = {
|
|||
|
searchInput: null,
|
|||
|
resultsContainer: null,
|
|||
|
json: [],
|
|||
|
success: Function.prototype,
|
|||
|
searchResultTemplate: '<li><a href="{url}" title="{desc}">{title}</a></li>',
|
|||
|
templateMiddleware: Function.prototype,
|
|||
|
sortMiddleware: function () {
|
|||
|
return 0
|
|||
|
},
|
|||
|
noResultsText: 'No results found',
|
|||
|
limit: 10,
|
|||
|
fuzzy: false,
|
|||
|
debounceTime: null,
|
|||
|
exclude: []
|
|||
|
}
|
|||
|
|
|||
|
let debounceTimerHandle
|
|||
|
const debounce = function (func, delayMillis) {
|
|||
|
if (delayMillis) {
|
|||
|
clearTimeout(debounceTimerHandle)
|
|||
|
debounceTimerHandle = setTimeout(func, delayMillis)
|
|||
|
} else {
|
|||
|
func.call()
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
const requiredOptions = ['searchInput', 'resultsContainer', 'json']
|
|||
|
|
|||
|
/* removed: const _$Templater_7 = require('./Templater') */;
|
|||
|
/* removed: const _$Repository_4 = require('./Repository') */;
|
|||
|
/* removed: const _$JSONLoader_2 = require('./JSONLoader') */;
|
|||
|
const optionsValidator = _$OptionsValidator_3({
|
|||
|
required: requiredOptions
|
|||
|
})
|
|||
|
/* removed: const _$utils_9 = require('./utils') */;
|
|||
|
|
|||
|
window.SimpleJekyllSearch = function (_options) {
|
|||
|
const errors = optionsValidator.validate(_options)
|
|||
|
if (errors.length > 0) {
|
|||
|
throwError('You must specify the following required options: ' + requiredOptions)
|
|||
|
}
|
|||
|
|
|||
|
options = _$utils_9.merge(options, _options)
|
|||
|
|
|||
|
_$Templater_7.setOptions({
|
|||
|
template: options.searchResultTemplate,
|
|||
|
middleware: options.templateMiddleware
|
|||
|
})
|
|||
|
|
|||
|
_$Repository_4.setOptions({
|
|||
|
fuzzy: options.fuzzy,
|
|||
|
limit: options.limit,
|
|||
|
sort: options.sortMiddleware,
|
|||
|
exclude: options.exclude
|
|||
|
})
|
|||
|
|
|||
|
if (_$utils_9.isJSON(options.json)) {
|
|||
|
initWithJSON(options.json)
|
|||
|
} else {
|
|||
|
initWithURL(options.json)
|
|||
|
}
|
|||
|
|
|||
|
const rv = {
|
|||
|
search: search
|
|||
|
}
|
|||
|
|
|||
|
typeof options.success === 'function' && options.success.call(rv)
|
|||
|
return rv
|
|||
|
}
|
|||
|
|
|||
|
function initWithJSON (json) {
|
|||
|
_$Repository_4.put(json)
|
|||
|
registerInput()
|
|||
|
}
|
|||
|
|
|||
|
function initWithURL (url) {
|
|||
|
_$JSONLoader_2.load(url, function (err, json) {
|
|||
|
if (err) {
|
|||
|
throwError('failed to get JSON (' + url + ')')
|
|||
|
}
|
|||
|
initWithJSON(json)
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
function emptyResultsContainer () {
|
|||
|
options.resultsContainer.innerHTML = ''
|
|||
|
}
|
|||
|
|
|||
|
function appendToResultsContainer (text) {
|
|||
|
options.resultsContainer.innerHTML += text
|
|||
|
}
|
|||
|
|
|||
|
function registerInput () {
|
|||
|
options.searchInput.addEventListener('input', function (e) {
|
|||
|
if (isWhitelistedKey(e.which)) {
|
|||
|
emptyResultsContainer()
|
|||
|
debounce(function () { search(e.target.value) }, options.debounceTime)
|
|||
|
}
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
function search (query) {
|
|||
|
if (isValidQuery(query)) {
|
|||
|
emptyResultsContainer()
|
|||
|
render(_$Repository_4.search(query), query)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function render (results, query) {
|
|||
|
const len = results.length
|
|||
|
if (len === 0) {
|
|||
|
return appendToResultsContainer(options.noResultsText)
|
|||
|
}
|
|||
|
for (let i = 0; i < len; i++) {
|
|||
|
results[i].query = query
|
|||
|
appendToResultsContainer(_$Templater_7.compile(results[i]))
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function isValidQuery (query) {
|
|||
|
return query && query.length > 0
|
|||
|
}
|
|||
|
|
|||
|
function isWhitelistedKey (key) {
|
|||
|
return [13, 16, 20, 37, 38, 39, 40, 91].indexOf(key) === -1
|
|||
|
}
|
|||
|
|
|||
|
function throwError (message) {
|
|||
|
throw new Error('SimpleJekyllSearch --- ' + message)
|
|||
|
}
|
|||
|
})(window)
|
|||
|
|
|||
|
}());
|
|||
|
</script>
|
|||
|
|
|||
|
<!-- Configuration -->
|
|||
|
<script>
|
|||
|
SimpleJekyllSearch({
|
|||
|
searchInput: document.getElementById('search-input'),
|
|||
|
resultsContainer: document.getElementById('results-container'),
|
|||
|
noResultsText: '<p>Aucun résultat!</p>',
|
|||
|
json: '/search.json',
|
|||
|
searchResultTemplate: '<li><a href="{url}">{date} {title}</a> (Création {create})</li>'
|
|||
|
})
|
|||
|
</script>
|
|||
|
|
|||
|
</div></div>
|
|||
|
|
|||
|
|
|||
|
<script>(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
function scrollToAnchor(anchor, duration, callback) {
|
|||
|
var $root = this;
|
|||
|
$root.animate({ scrollTop: $(anchor).position().top }, duration, function() {
|
|||
|
window.history.replaceState(null, '', window.location.href.split('#')[0] + anchor);
|
|||
|
callback && callback();
|
|||
|
});
|
|||
|
}
|
|||
|
$.fn.scrollToAnchor = scrollToAnchor;
|
|||
|
});
|
|||
|
})();
|
|||
|
(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
function affix(options) {
|
|||
|
var $root = this, $window = $(window), $scrollTarget, $scroll,
|
|||
|
offsetBottom = 0, scrollTarget = window, scroll = window.document, disabled = false, isOverallScroller = true,
|
|||
|
rootTop, rootLeft, rootHeight, scrollBottom, rootBottomTop,
|
|||
|
hasInit = false, curState;
|
|||
|
|
|||
|
function setOptions(options) {
|
|||
|
var _options = options || {};
|
|||
|
_options.offsetBottom && (offsetBottom = _options.offsetBottom);
|
|||
|
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
|
|||
|
_options.scroll && (scroll = _options.scroll);
|
|||
|
_options.disabled !== undefined && (disabled = _options.disabled);
|
|||
|
$scrollTarget = $(scrollTarget);
|
|||
|
isOverallScroller = window.isOverallScroller($scrollTarget[0]);
|
|||
|
$scroll = $(scroll);
|
|||
|
}
|
|||
|
function preCalc() {
|
|||
|
top();
|
|||
|
rootHeight = $root.outerHeight();
|
|||
|
rootTop = $root.offset().top + (isOverallScroller ? 0 : $scrollTarget.scrollTop());
|
|||
|
rootLeft = $root.offset().left;
|
|||
|
}
|
|||
|
function calc(needPreCalc) {
|
|||
|
needPreCalc && preCalc();
|
|||
|
scrollBottom = $scroll.outerHeight() - offsetBottom - rootHeight;
|
|||
|
rootBottomTop = scrollBottom - rootTop;
|
|||
|
}
|
|||
|
function top() {
|
|||
|
if (curState !== 'top') {
|
|||
|
$root.removeClass('fixed').css({
|
|||
|
left: 0,
|
|||
|
top: 0
|
|||
|
});
|
|||
|
curState = 'top';
|
|||
|
}
|
|||
|
}
|
|||
|
function fixed() {
|
|||
|
if (curState !== 'fixed') {
|
|||
|
$root.addClass('fixed').css({
|
|||
|
left: rootLeft + 'px',
|
|||
|
top: 0
|
|||
|
});
|
|||
|
curState = 'fixed';
|
|||
|
}
|
|||
|
}
|
|||
|
function bottom() {
|
|||
|
if (curState !== 'bottom') {
|
|||
|
$root.removeClass('fixed').css({
|
|||
|
left: 0,
|
|||
|
top: rootBottomTop + 'px'
|
|||
|
});
|
|||
|
curState = 'bottom';
|
|||
|
}
|
|||
|
}
|
|||
|
function setState() {
|
|||
|
var scrollTop = $scrollTarget.scrollTop();
|
|||
|
if (scrollTop >= rootTop && scrollTop <= scrollBottom) {
|
|||
|
fixed();
|
|||
|
} else if (scrollTop < rootTop) {
|
|||
|
top();
|
|||
|
} else {
|
|||
|
bottom();
|
|||
|
}
|
|||
|
}
|
|||
|
function init() {
|
|||
|
if(!hasInit) {
|
|||
|
var interval, timeout;
|
|||
|
calc(true); setState();
|
|||
|
// run calc every 100 millisecond
|
|||
|
interval = setInterval(function() {
|
|||
|
calc();
|
|||
|
}, 100);
|
|||
|
timeout = setTimeout(function() {
|
|||
|
clearInterval(interval);
|
|||
|
}, 45000);
|
|||
|
window.pageLoad.then(function() {
|
|||
|
setTimeout(function() {
|
|||
|
clearInterval(interval);
|
|||
|
clearTimeout(timeout);
|
|||
|
}, 3000);
|
|||
|
});
|
|||
|
$scrollTarget.on('scroll', function() {
|
|||
|
disabled || setState();
|
|||
|
});
|
|||
|
$window.on('resize', function() {
|
|||
|
disabled || (calc(true), setState());
|
|||
|
});
|
|||
|
hasInit = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
setOptions(options);
|
|||
|
if (!disabled) {
|
|||
|
init();
|
|||
|
}
|
|||
|
$window.on('resize', window.throttle(function() {
|
|||
|
init();
|
|||
|
}, 200));
|
|||
|
return {
|
|||
|
setOptions: setOptions,
|
|||
|
refresh: function() {
|
|||
|
calc(true, { animation: false }); setState();
|
|||
|
}
|
|||
|
};
|
|||
|
}
|
|||
|
$.fn.affix = affix;
|
|||
|
});
|
|||
|
})();
|
|||
|
(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
function toc(options) {
|
|||
|
var $root = this, $window = $(window), $scrollTarget, $scroller, $tocUl = $('<ul class="toc toc--ellipsis"></ul>'), $tocLi, $headings, $activeLast, $activeCur,
|
|||
|
selectors = 'h1,h2,h3', container = 'body', scrollTarget = window, scroller = 'html, body', disabled = false,
|
|||
|
headingsPos, scrolling = false, hasRendered = false, hasInit = false;
|
|||
|
|
|||
|
function setOptions(options) {
|
|||
|
var _options = options || {};
|
|||
|
_options.selectors && (selectors = _options.selectors);
|
|||
|
_options.container && (container = _options.container);
|
|||
|
_options.scrollTarget && (scrollTarget = _options.scrollTarget);
|
|||
|
_options.scroller && (scroller = _options.scroller);
|
|||
|
_options.disabled !== undefined && (disabled = _options.disabled);
|
|||
|
$headings = $(container).find(selectors).filter('[id]');
|
|||
|
$scrollTarget = $(scrollTarget);
|
|||
|
$scroller = $(scroller);
|
|||
|
}
|
|||
|
function calc() {
|
|||
|
headingsPos = [];
|
|||
|
$headings.each(function() {
|
|||
|
headingsPos.push(Math.floor($(this).position().top));
|
|||
|
});
|
|||
|
}
|
|||
|
function setState(element, disabled) {
|
|||
|
var scrollTop = $scrollTarget.scrollTop(), i;
|
|||
|
if (disabled || !headingsPos || headingsPos.length < 1) { return; }
|
|||
|
if (element) {
|
|||
|
$activeCur = element;
|
|||
|
} else {
|
|||
|
for (i = 0; i < headingsPos.length; i++) {
|
|||
|
if (scrollTop >= headingsPos[i]) {
|
|||
|
$activeCur = $tocLi.eq(i);
|
|||
|
} else {
|
|||
|
$activeCur || ($activeCur = $tocLi.eq(i));
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
$activeLast && $activeLast.removeClass('active');
|
|||
|
($activeLast = $activeCur).addClass('active');
|
|||
|
}
|
|||
|
function render() {
|
|||
|
if(!hasRendered) {
|
|||
|
$root.append($tocUl);
|
|||
|
$headings.each(function() {
|
|||
|
var $this = $(this);
|
|||
|
$tocUl.append($('<li></li>').addClass('toc-' + $this.prop('tagName').toLowerCase())
|
|||
|
.append($('<a></a>').text($this.text()).attr('href', '#' + $this.prop('id'))));
|
|||
|
});
|
|||
|
$tocLi = $tocUl.children('li');
|
|||
|
$tocUl.on('click', 'a', function(e) {
|
|||
|
e.preventDefault();
|
|||
|
var $this = $(this);
|
|||
|
scrolling = true;
|
|||
|
setState($this.parent());
|
|||
|
$scroller.scrollToAnchor($this.attr('href'), 400, function() {
|
|||
|
scrolling = false;
|
|||
|
});
|
|||
|
});
|
|||
|
}
|
|||
|
hasRendered = true;
|
|||
|
}
|
|||
|
function init() {
|
|||
|
var interval, timeout;
|
|||
|
if(!hasInit) {
|
|||
|
render(); calc(); setState(null, scrolling);
|
|||
|
// run calc every 100 millisecond
|
|||
|
interval = setInterval(function() {
|
|||
|
calc();
|
|||
|
}, 100);
|
|||
|
timeout = setTimeout(function() {
|
|||
|
clearInterval(interval);
|
|||
|
}, 45000);
|
|||
|
window.pageLoad.then(function() {
|
|||
|
setTimeout(function() {
|
|||
|
clearInterval(interval);
|
|||
|
clearTimeout(timeout);
|
|||
|
}, 3000);
|
|||
|
});
|
|||
|
$scrollTarget.on('scroll', function() {
|
|||
|
disabled || setState(null, scrolling);
|
|||
|
});
|
|||
|
$window.on('resize', window.throttle(function() {
|
|||
|
if (!disabled) {
|
|||
|
render(); calc(); setState(null, scrolling);
|
|||
|
}
|
|||
|
}, 100));
|
|||
|
}
|
|||
|
hasInit = true;
|
|||
|
}
|
|||
|
|
|||
|
setOptions(options);
|
|||
|
if (!disabled) {
|
|||
|
init();
|
|||
|
}
|
|||
|
$window.on('resize', window.throttle(function() {
|
|||
|
init();
|
|||
|
}, 200));
|
|||
|
return {
|
|||
|
setOptions: setOptions
|
|||
|
};
|
|||
|
}
|
|||
|
$.fn.toc = toc;
|
|||
|
});
|
|||
|
})();
|
|||
|
/*(function () {
|
|||
|
|
|||
|
})();*/
|
|||
|
</script><script>
|
|||
|
/* toc must before affix, since affix need to konw toc' height. */(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
var TOC_SELECTOR = window.TEXT_VARIABLES.site.toc.selectors;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
var $window = $(window);
|
|||
|
var $articleContent = $('.js-article-content');
|
|||
|
var $tocRoot = $('.js-toc-root'), $col2 = $('.js-col-aside');
|
|||
|
var toc;
|
|||
|
var tocDisabled = false;
|
|||
|
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
|
|||
|
var hasToc = $articleContent.find(TOC_SELECTOR).length > 0;
|
|||
|
|
|||
|
function disabled() {
|
|||
|
return $col2.css('display') === 'none' || !hasToc;
|
|||
|
}
|
|||
|
|
|||
|
tocDisabled = disabled();
|
|||
|
|
|||
|
toc = $tocRoot.toc({
|
|||
|
selectors: TOC_SELECTOR,
|
|||
|
container: $articleContent,
|
|||
|
scrollTarget: hasSidebar ? '.js-page-main' : null,
|
|||
|
scroller: hasSidebar ? '.js-page-main' : null,
|
|||
|
disabled: tocDisabled
|
|||
|
});
|
|||
|
|
|||
|
$window.on('resize', window.throttle(function() {
|
|||
|
tocDisabled = disabled();
|
|||
|
toc && toc.setOptions({
|
|||
|
disabled: tocDisabled
|
|||
|
});
|
|||
|
}, 100));
|
|||
|
|
|||
|
});
|
|||
|
})();
|
|||
|
(function() {
|
|||
|
var SOURCES = window.TEXT_VARIABLES.sources;
|
|||
|
window.Lazyload.js(SOURCES.jquery, function() {
|
|||
|
var $window = $(window), $pageFooter = $('.js-page-footer');
|
|||
|
var $pageAside = $('.js-page-aside');
|
|||
|
var affix;
|
|||
|
var tocDisabled = false;
|
|||
|
var hasSidebar = $('.js-page-root').hasClass('layout--page--sidebar');
|
|||
|
|
|||
|
affix = $pageAside.affix({
|
|||
|
offsetBottom: $pageFooter.outerHeight(),
|
|||
|
scrollTarget: hasSidebar ? '.js-page-main' : null,
|
|||
|
scroller: hasSidebar ? '.js-page-main' : null,
|
|||
|
scroll: hasSidebar ? $('.js-page-main').children() : null,
|
|||
|
disabled: tocDisabled
|
|||
|
});
|
|||
|
|
|||
|
$window.on('resize', window.throttle(function() {
|
|||
|
affix && affix.setOptions({
|
|||
|
disabled: tocDisabled
|
|||
|
});
|
|||
|
}, 100));
|
|||
|
|
|||
|
window.pageAsideAffix = affix;
|
|||
|
});
|
|||
|
})();
|
|||
|
</script><!---->
|
|||
|
|
|||
|
</div>
|
|||
|
<script>(function () {
|
|||
|
var $root = document.getElementsByClassName('root')[0];
|
|||
|
if (window.hasEvent('touchstart')) {
|
|||
|
$root.dataset.isTouch = true;
|
|||
|
document.addEventListener('touchstart', function(){}, false);
|
|||
|
}
|
|||
|
})();
|
|||
|
</script>
|
|||
|
</body>
|
|||
|
</html>
|
|||
|
|